Merge pull request #1522 from jcowgill/sfml-2.1
Update / Port to SFML 2.1
This commit is contained in:
commit
b806680eac
|
@ -600,16 +600,15 @@ if(LIBUSB_FOUND)
|
||||||
include_directories(${LIBUSB_INCLUDE_DIR})
|
include_directories(${LIBUSB_INCLUDE_DIR})
|
||||||
endif(LIBUSB_FOUND)
|
endif(LIBUSB_FOUND)
|
||||||
|
|
||||||
set(SFML_FIND_VERSION TRUE)
|
set(SFML_REQD_VERSION 2.1)
|
||||||
set(SFML_FIND_VERSION_MAJOR 1)
|
|
||||||
set(SFML_FIND_VERSION_MINOR 5)
|
|
||||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ANDROID)
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ANDROID)
|
||||||
include(FindSFML OPTIONAL)
|
find_package(SFML ${SFML_REQD_VERSION} COMPONENTS network system)
|
||||||
endif()
|
endif()
|
||||||
if(SFML_FOUND AND NOT SFML_VERSION_MAJOR) # SFML 1.x doesn't define SFML_VERSION_MAJOR
|
if(SFML_FOUND)
|
||||||
message("Using shared SFML")
|
message("Using shared SFML")
|
||||||
else()
|
else()
|
||||||
message("Using static SFML ${SFML_FIND_VERSION_MAJOR}.${SFML_FIND_VERSION_MINOR} from Externals")
|
message("Using static SFML ${SFML_REQD_VERSION} from Externals")
|
||||||
|
add_definitions(-DSFML_STATIC)
|
||||||
add_subdirectory(Externals/SFML)
|
add_subdirectory(Externals/SFML)
|
||||||
include_directories(BEFORE Externals/SFML/include)
|
include_directories(BEFORE Externals/SFML/include)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,20 +1,59 @@
|
||||||
# Locate the SFML library
|
# This script locates the SFML library
|
||||||
|
# ------------------------------------
|
||||||
#
|
#
|
||||||
# This module defines the following variables:
|
# Usage
|
||||||
# - For each module XXX (SYSTEM, WINDOW, GRAPHICS, NETWORK, AUDIO, MAIN):
|
# -----
|
||||||
# - SFML_XXX_LIBRARY_DEBUG, the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found)
|
#
|
||||||
# - SFML_XXX_LIBRARY_RELEASE, the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found)
|
# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main).
|
||||||
# - SFML_XXX_LIBRARY, the name of the library to link to for the xxx module (includes both debug and optimized names if necessary)
|
# If none is given, the SFML_LIBRARIES variable will be empty and you'll end up linking to nothing.
|
||||||
# - SFML_XXX_FOUND, true if either the debug or release library of the xxx module is found
|
# example:
|
||||||
# - SFML_LIBRARIES, the list of all libraries corresponding to the required modules
|
# find_package(SFML COMPONENTS graphics window system) // find the graphics, window and system modules
|
||||||
# - SFML_FOUND, true if all the required modules are found
|
#
|
||||||
# - SFML_INCLUDE_DIR, the path where SFML headers are located (the directory containing the SFML/Config.hpp file)
|
# You can enforce a specific version, either MAJOR.MINOR or only MAJOR.
|
||||||
|
# If nothing is specified, the version won't be checked (ie. any version will be accepted).
|
||||||
|
# example:
|
||||||
|
# find_package(SFML COMPONENTS ...) // no specific version required
|
||||||
|
# find_package(SFML 2 COMPONENTS ...) // any 2.x version
|
||||||
|
# find_package(SFML 2.4 COMPONENTS ...) // version 2.4 or greater
|
||||||
#
|
#
|
||||||
# By default, the dynamic libraries of SFML will be found. To find the static ones instead,
|
# By default, the dynamic libraries of SFML will be found. To find the static ones instead,
|
||||||
# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...).
|
# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...).
|
||||||
|
# In case of static linking, the SFML_STATIC macro will also be defined by this script.
|
||||||
|
# example:
|
||||||
|
# set(SFML_STATIC_LIBRARIES TRUE)
|
||||||
|
# find_package(SFML 2 COMPONENTS network system)
|
||||||
#
|
#
|
||||||
# If SFML is not installed in a standard path, you can use the SFMLDIR CMake variable or environment variable
|
# On Mac OS X if SFML_STATIC_LIBRARIES is not set to TRUE then by default CMake will search for frameworks unless
|
||||||
|
# CMAKE_FIND_FRAMEWORK is set to "NEVER" for example. Please refer to CMake documentation for more details.
|
||||||
|
# Moreover, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which
|
||||||
|
# are available for both release and debug modes.
|
||||||
|
#
|
||||||
|
# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable
|
||||||
# to tell CMake where SFML is.
|
# to tell CMake where SFML is.
|
||||||
|
#
|
||||||
|
# Output
|
||||||
|
# ------
|
||||||
|
#
|
||||||
|
# This script defines the following variables:
|
||||||
|
# - For each specified module XXX (system, window, graphics, network, audio, main):
|
||||||
|
# - SFML_XXX_LIBRARY_DEBUG: the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found)
|
||||||
|
# - SFML_XXX_LIBRARY_RELEASE: the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found)
|
||||||
|
# - SFML_XXX_LIBRARY: the name of the library to link to for the xxx module (includes both debug and optimized names if necessary)
|
||||||
|
# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found
|
||||||
|
# - SFML_LIBRARIES: the list of all libraries corresponding to the required modules
|
||||||
|
# - SFML_FOUND: true if all the required modules are found
|
||||||
|
# - SFML_INCLUDE_DIR: the path where SFML headers are located (the directory containing the SFML/Config.hpp file)
|
||||||
|
#
|
||||||
|
# example:
|
||||||
|
# find_package(SFML 2 COMPONENTS system window graphics audio REQUIRED)
|
||||||
|
# include_directories(${SFML_INCLUDE_DIR})
|
||||||
|
# add_executable(myapp ...)
|
||||||
|
# target_link_libraries(myapp ${SFML_LIBRARIES})
|
||||||
|
|
||||||
|
# define the SFML_STATIC macro if static build was chosen
|
||||||
|
if(SFML_STATIC_LIBRARIES)
|
||||||
|
add_definitions(-DSFML_STATIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
# deduce the libraries suffix from the options
|
# deduce the libraries suffix from the options
|
||||||
set(FIND_SFML_LIB_SUFFIX "")
|
set(FIND_SFML_LIB_SUFFIX "")
|
||||||
|
@ -26,6 +65,8 @@ endif()
|
||||||
find_path(SFML_INCLUDE_DIR SFML/Config.hpp
|
find_path(SFML_INCLUDE_DIR SFML/Config.hpp
|
||||||
PATH_SUFFIXES include
|
PATH_SUFFIXES include
|
||||||
PATHS
|
PATHS
|
||||||
|
${SFML_ROOT}
|
||||||
|
$ENV{SFML_ROOT}
|
||||||
~/Library/Frameworks
|
~/Library/Frameworks
|
||||||
/Library/Frameworks
|
/Library/Frameworks
|
||||||
/usr/local/
|
/usr/local/
|
||||||
|
@ -33,19 +74,19 @@ find_path(SFML_INCLUDE_DIR SFML/Config.hpp
|
||||||
/sw # Fink
|
/sw # Fink
|
||||||
/opt/local/ # DarwinPorts
|
/opt/local/ # DarwinPorts
|
||||||
/opt/csw/ # Blastwave
|
/opt/csw/ # Blastwave
|
||||||
/opt/
|
/opt/)
|
||||||
${SFMLDIR}
|
|
||||||
$ENV{SFMLDIR})
|
|
||||||
|
|
||||||
|
|
||||||
# will be set to false if one of the required modules is not found
|
|
||||||
set(SFML_FOUND TRUE)
|
|
||||||
set(SFML_VERSION_OK TRUE)
|
|
||||||
|
|
||||||
# check the version number
|
# check the version number
|
||||||
if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR AND NOT (SFML_INCLUDE_DIR STREQUAL "SFML_INCLUDE_DIR-NOTFOUND"))
|
set(SFML_VERSION_OK TRUE)
|
||||||
|
if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR)
|
||||||
# extract the major and minor version numbers from SFML/Config.hpp
|
# extract the major and minor version numbers from SFML/Config.hpp
|
||||||
FILE(READ "${SFML_INCLUDE_DIR}/SFML/Config.hpp" SFML_CONFIG_HPP_CONTENTS)
|
# we have to handle framework a little bit differently :
|
||||||
|
if("${SFML_INCLUDE_DIR}" MATCHES "SFML.framework")
|
||||||
|
set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/Headers/Config.hpp")
|
||||||
|
else()
|
||||||
|
set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/SFML/Config.hpp")
|
||||||
|
endif()
|
||||||
|
FILE(READ "${SFML_CONFIG_HPP_INPUT}" SFML_CONFIG_HPP_CONTENTS)
|
||||||
STRING(REGEX MATCH ".*#define SFML_VERSION_MAJOR ([0-9]+).*#define SFML_VERSION_MINOR ([0-9]+).*" SFML_CONFIG_HPP_CONTENTS "${SFML_CONFIG_HPP_CONTENTS}")
|
STRING(REGEX MATCH ".*#define SFML_VERSION_MAJOR ([0-9]+).*#define SFML_VERSION_MINOR ([0-9]+).*" SFML_CONFIG_HPP_CONTENTS "${SFML_CONFIG_HPP_CONTENTS}")
|
||||||
STRING(REGEX REPLACE ".*#define SFML_VERSION_MAJOR ([0-9]+).*" "\\1" SFML_VERSION_MAJOR "${SFML_CONFIG_HPP_CONTENTS}")
|
STRING(REGEX REPLACE ".*#define SFML_VERSION_MAJOR ([0-9]+).*" "\\1" SFML_VERSION_MAJOR "${SFML_CONFIG_HPP_CONTENTS}")
|
||||||
STRING(REGEX REPLACE ".*#define SFML_VERSION_MINOR ([0-9]+).*" "\\1" SFML_VERSION_MINOR "${SFML_CONFIG_HPP_CONTENTS}")
|
STRING(REGEX REPLACE ".*#define SFML_VERSION_MINOR ([0-9]+).*" "\\1" SFML_VERSION_MINOR "${SFML_CONFIG_HPP_CONTENTS}")
|
||||||
|
@ -68,22 +109,21 @@ if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR AND NOT (SFML_INCLUDE_DIR STREQUAL "SF
|
||||||
set(SFML_VERSION_MINOR x)
|
set(SFML_VERSION_MINOR x)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
elseif(SFML_INCLUDE_DIR STREQUAL "SFML_INCLUDE_DIR-NOTFOUND")
|
|
||||||
set(SFML_FOUND FALSE)
|
|
||||||
set(FIND_SFML_MISSING "${FIND_SFML_MISSING} SFML_INCLUDE_DIR")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# find the requested modules
|
# find the requested modules
|
||||||
set(FIND_SFML_LIB_PATHS ~/Library/Frameworks
|
set(SFML_FOUND TRUE) # will be set to false if one of the required modules is not found
|
||||||
|
set(FIND_SFML_LIB_PATHS
|
||||||
|
${SFML_ROOT}
|
||||||
|
$ENV{SFML_ROOT}
|
||||||
|
~/Library/Frameworks
|
||||||
/Library/Frameworks
|
/Library/Frameworks
|
||||||
/usr/local
|
/usr/local
|
||||||
/usr
|
/usr
|
||||||
/sw
|
/sw
|
||||||
/opt/local
|
/opt/local
|
||||||
/opt/csw
|
/opt/csw
|
||||||
/opt
|
/opt)
|
||||||
${SFMLDIR}
|
|
||||||
$ENV{SFMLDIR})
|
|
||||||
foreach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS})
|
foreach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS})
|
||||||
string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER)
|
string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER)
|
||||||
string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER)
|
string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER)
|
||||||
|
@ -165,5 +205,5 @@ endif()
|
||||||
|
|
||||||
# handle success
|
# handle success
|
||||||
if(SFML_FOUND)
|
if(SFML_FOUND)
|
||||||
message("Found SFML: ${SFML_INCLUDE_DIR}")
|
message(STATUS "Found SFML ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR} in ${SFML_INCLUDE_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
include_directories(BEFORE include)
|
include_directories(BEFORE include src)
|
||||||
|
|
||||||
set(SRCS src/SFML/Network/Ftp.cpp
|
set(SRC_NETWORK
|
||||||
src/SFML/Network/Http.cpp
|
src/SFML/Network/Http.cpp
|
||||||
src/SFML/Network/IPAddress.cpp
|
src/SFML/Network/IPAddress.cpp
|
||||||
src/SFML/Network/Packet.cpp
|
src/SFML/Network/Packet.cpp
|
||||||
src/SFML/Network/SelectorBase.cpp
|
src/SFML/Network/Socket.cpp
|
||||||
src/SFML/Network/SocketTCP.cpp
|
src/SFML/Network/SocketSelector.cpp
|
||||||
src/SFML/Network/SocketUDP.cpp)
|
src/SFML/Network/TcpListener.cpp
|
||||||
|
src/SFML/Network/TcpSocket.cpp
|
||||||
|
src/SFML/Network/UdpSocket.cpp
|
||||||
|
)
|
||||||
|
|
||||||
if(UNIX)
|
if(WIN32)
|
||||||
set(SRCS ${SRCS} src/SFML/Network/Unix/SocketHelper.cpp)
|
list(APPEND SRC_NETWORK src/SFML/Network/Win32/SocketImpl.cpp)
|
||||||
elseif(WIN32)
|
else()
|
||||||
set(SRCS ${SRCS} src/SFML/Network/Win32/SocketHelper.cpp)
|
list(APPEND SRC_NETWORK src/SFML/Network/Unix/SocketImpl.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(sfml-network ${SRCS})
|
set(SRC_SYSTEM
|
||||||
|
src/SFML/System/Err.cpp
|
||||||
|
src/SFML/System/String.cpp
|
||||||
|
src/SFML/System/Time.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(sfml-network ${SRC_NETWORK})
|
||||||
|
add_library(sfml-system ${SRC_SYSTEM})
|
||||||
|
|
|
@ -42,31 +42,48 @@
|
||||||
<Import Project="..\..\..\..\Source\VSProps\ClDisableAllWarnings.props" />
|
<Import Project="..\..\..\..\Source\VSProps\ClDisableAllWarnings.props" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>..\..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Ftp.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Http.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\Http.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\IPAddress.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\IPAddress.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Packet.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\Packet.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\SelectorBase.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\Socket.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\SocketTCP.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\SocketSelector.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\SocketUDP.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\TcpListener.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Win32\SocketHelper.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\TcpSocket.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\Network\UdpSocket.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\Network\Win32\SocketImpl.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\System\Err.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\System\String.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\System\Time.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Ftp.hpp" />
|
<ClInclude Include="..\..\include\SFML\Config.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\Network.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\Network\Export.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Http.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\Http.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\IPAddress.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\IPAddress.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Packet.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\Packet.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Selector.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\Socket.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SelectorBase.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\SocketHandle.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SocketHelper.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\SocketSelector.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Sockets.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\TcpListener.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SocketTCP.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\TcpSocket.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SocketUDP.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\UdpSocket.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Win32\SocketHelper.hpp" />
|
<ClInclude Include="..\..\include\SFML\System.hpp" />
|
||||||
</ItemGroup>
|
<ClInclude Include="..\..\include\SFML\System\Err.hpp" />
|
||||||
<ItemGroup>
|
<ClInclude Include="..\..\include\SFML\System\Export.hpp" />
|
||||||
<None Include="..\..\include\SFML\Network\Selector.inl" />
|
<ClInclude Include="..\..\include\SFML\System\NonCopyable.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\String.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Time.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Utf.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Utf.inl" />
|
||||||
|
<ClInclude Include="..\..\src\SFML\Network\SocketImpl.hpp" />
|
||||||
|
<ClInclude Include="..\..\src\SFML\Network\Win32\SocketImpl.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
@ -1,35 +1,47 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Ftp.cpp" />
|
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Http.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\Http.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\IPAddress.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\IPAddress.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Packet.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\Packet.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\SelectorBase.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\Socket.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\SocketTCP.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\SocketSelector.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\SocketUDP.cpp" />
|
<ClCompile Include="..\..\src\SFML\Network\TcpListener.cpp" />
|
||||||
<ClCompile Include="..\..\src\SFML\Network\Win32\SocketHelper.cpp">
|
<ClCompile Include="..\..\src\SFML\Network\TcpSocket.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\Network\UdpSocket.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\Network\Win32\SocketImpl.cpp">
|
||||||
<Filter>Win32</Filter>
|
<Filter>Win32</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\SFML\System\Err.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\System\String.cpp" />
|
||||||
|
<ClCompile Include="..\..\src\SFML\System\Time.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Ftp.hpp" />
|
<ClInclude Include="..\..\include\SFML\Config.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\Network.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\Network\Export.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Http.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\Http.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\IPAddress.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\IPAddress.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Packet.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\Packet.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Selector.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\Socket.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SelectorBase.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\SocketHandle.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SocketHelper.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\SocketSelector.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Sockets.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\TcpListener.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SocketTCP.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\TcpSocket.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\SocketUDP.hpp" />
|
<ClInclude Include="..\..\include\SFML\Network\UdpSocket.hpp" />
|
||||||
<ClInclude Include="..\..\include\SFML\Network\Win32\SocketHelper.hpp">
|
<ClInclude Include="..\..\include\SFML\System.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Err.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Export.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\NonCopyable.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\String.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Time.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Utf.hpp" />
|
||||||
|
<ClInclude Include="..\..\include\SFML\System\Utf.inl" />
|
||||||
|
<ClInclude Include="..\..\src\SFML\Network\SocketImpl.hpp" />
|
||||||
|
<ClInclude Include="..\..\src\SFML\Network\Win32\SocketImpl.hpp">
|
||||||
<Filter>Win32</Filter>
|
<Filter>Win32</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\..\include\SFML\Network\Selector.inl" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Win32">
|
<Filter Include="Win32">
|
||||||
<UniqueIdentifier>{8280ecca-24fc-48a2-b7f5-6aca41826b66}</UniqueIdentifier>
|
<UniqueIdentifier>{8280ecca-24fc-48a2-b7f5-6aca41826b66}</UniqueIdentifier>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -25,6 +25,14 @@
|
||||||
#ifndef SFML_CONFIG_HPP
|
#ifndef SFML_CONFIG_HPP
|
||||||
#define SFML_CONFIG_HPP
|
#define SFML_CONFIG_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Define the SFML version
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#define SFML_VERSION_MAJOR 2
|
||||||
|
#define SFML_VERSION_MINOR 1
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Identify the operating system
|
// Identify the operating system
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -32,9 +40,6 @@
|
||||||
|
|
||||||
// Windows
|
// Windows
|
||||||
#define SFML_SYSTEM_WINDOWS
|
#define SFML_SYSTEM_WINDOWS
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,8 +54,7 @@
|
||||||
// MacOS
|
// MacOS
|
||||||
#define SFML_SYSTEM_MACOS
|
#define SFML_SYSTEM_MACOS
|
||||||
|
|
||||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
defined(__NetBSD__) || defined(__OpenBSD__)
|
|
||||||
|
|
||||||
// FreeBSD
|
// FreeBSD
|
||||||
#define SFML_SYSTEM_FREEBSD
|
#define SFML_SYSTEM_FREEBSD
|
||||||
|
@ -74,45 +78,47 @@
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Define portable import / export macros
|
// Define helpers to create portable import / export macros for each module
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#if defined(SFML_SYSTEM_WINDOWS)
|
#if !defined(SFML_STATIC)
|
||||||
|
|
||||||
#ifdef SFML_DYNAMIC
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
|
||||||
// Windows platforms
|
// Windows compilers need specific (and different) keywords for export and import
|
||||||
#ifdef SFML_EXPORTS
|
#define SFML_API_EXPORT __declspec(dllexport)
|
||||||
|
#define SFML_API_IMPORT __declspec(dllimport)
|
||||||
|
|
||||||
// From DLL side, we must export
|
// For Visual C++ compilers, we also need to turn off this annoying C4251 warning
|
||||||
#define SFML_API __declspec(dllexport)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// From client application side, we must import
|
|
||||||
#define SFML_API __declspec(dllimport)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For Visual C++ compilers, we also need to turn off this annoying C4251 warning.
|
|
||||||
// You can read lots ot different things about it, but the point is the code will
|
|
||||||
// just work fine, and so the simplest way to get rid of this warning is to disable it
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
#pragma warning(disable : 4251)
|
#pragma warning(disable : 4251)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#else // Linux, FreeBSD, Mac OS X
|
||||||
|
|
||||||
|
#if __GNUC__ >= 4
|
||||||
|
|
||||||
|
// GCC 4 has special keywords for showing/hidding symbols,
|
||||||
|
// the same keyword is used for both importing and exporting
|
||||||
|
#define SFML_API_EXPORT __attribute__ ((__visibility__ ("default")))
|
||||||
|
#define SFML_API_IMPORT __attribute__ ((__visibility__ ("default")))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// No specific directive needed for static build
|
// GCC < 4 has no mechanism to explicitely hide symbols, everything's exported
|
||||||
#define SFML_API
|
#define SFML_API_EXPORT
|
||||||
|
#define SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Other platforms don't need to define anything
|
// Static build doesn't need import/export macros
|
||||||
#define SFML_API
|
#define SFML_API_EXPORT
|
||||||
|
#define SFML_API_IMPORT
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -120,44 +126,31 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Define portable fixed-size types
|
// Define portable fixed-size types
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <climits>
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
// All "common" platforms use the same size for char, short and int
|
||||||
|
// (basically there are 3 types for 3 sizes, so no other match is possible),
|
||||||
|
// we can use them without doing any kind of check
|
||||||
|
|
||||||
// 8 bits integer types
|
// 8 bits integer types
|
||||||
#if UCHAR_MAX == 0xFF
|
|
||||||
typedef signed char Int8;
|
typedef signed char Int8;
|
||||||
typedef unsigned char Uint8;
|
typedef unsigned char Uint8;
|
||||||
#else
|
|
||||||
#error No 8 bits integer type for this platform
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 16 bits integer types
|
// 16 bits integer types
|
||||||
#if USHRT_MAX == 0xFFFF
|
|
||||||
typedef signed short Int16;
|
typedef signed short Int16;
|
||||||
typedef unsigned short Uint16;
|
typedef unsigned short Uint16;
|
||||||
#elif UINT_MAX == 0xFFFF
|
|
||||||
typedef signed int Int16;
|
|
||||||
typedef unsigned int Uint16;
|
|
||||||
#elif ULONG_MAX == 0xFFFF
|
|
||||||
typedef signed long Int16;
|
|
||||||
typedef unsigned long Uint16;
|
|
||||||
#else
|
|
||||||
#error No 16 bits integer type for this platform
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 32 bits integer types
|
// 32 bits integer types
|
||||||
#if USHRT_MAX == 0xFFFFFFFF
|
|
||||||
typedef signed short Int32;
|
|
||||||
typedef unsigned short Uint32;
|
|
||||||
#elif UINT_MAX == 0xFFFFFFFF
|
|
||||||
typedef signed int Int32;
|
typedef signed int Int32;
|
||||||
typedef unsigned int Uint32;
|
typedef unsigned int Uint32;
|
||||||
#elif ULONG_MAX == 0xFFFFFFFF
|
|
||||||
typedef signed long Int32;
|
// 64 bits integer types
|
||||||
typedef unsigned long Uint32;
|
#if defined(_MSC_VER)
|
||||||
|
typedef signed __int64 Int64;
|
||||||
|
typedef unsigned __int64 Uint64;
|
||||||
#else
|
#else
|
||||||
#error No 32 bits integer type for this platform
|
typedef signed long long Int64;
|
||||||
|
typedef unsigned long long Uint64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -30,13 +30,24 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <SFML/System.hpp>
|
#include <SFML/System.hpp>
|
||||||
#include <SFML/Network/Ftp.hpp>
|
//#include <SFML/Network/Ftp.hpp>
|
||||||
#include <SFML/Network/Http.hpp>
|
#include <SFML/Network/Http.hpp>
|
||||||
|
|
||||||
|
// This file is "IpAddress.hpp" upstream
|
||||||
#include <SFML/Network/IPAddress.hpp>
|
#include <SFML/Network/IPAddress.hpp>
|
||||||
#include <SFML/Network/Packet.hpp>
|
#include <SFML/Network/Packet.hpp>
|
||||||
#include <SFML/Network/Selector.hpp>
|
#include <SFML/Network/SocketSelector.hpp>
|
||||||
#include <SFML/Network/SocketTCP.hpp>
|
#include <SFML/Network/TcpListener.hpp>
|
||||||
#include <SFML/Network/SocketUDP.hpp>
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
#include <SFML/Network/UdpSocket.hpp>
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_NETWORK_HPP
|
#endif // SFML_NETWORK_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \defgroup network Network module
|
||||||
|
///
|
||||||
|
/// Socket-based communication, utilities and higher-level
|
||||||
|
/// network protocols (HTTP, FTP).
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_NETWORK_EXPORT_HPP
|
||||||
|
#define SFML_NETWORK_EXPORT_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Define portable import / export macros
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_NETWORK_EXPORTS)
|
||||||
|
|
||||||
|
#define SFML_NETWORK_API SFML_API_EXPORT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_NETWORK_API SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_NETWORK_EXPORT_HPP
|
|
@ -1,448 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef SFML_FTP_HPP
|
|
||||||
#define SFML_FTP_HPP
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/System/NonCopyable.hpp>
|
|
||||||
#include <SFML/Network/SocketTCP.hpp>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
class IPAddress;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// This class provides methods for manipulating the FTP
|
|
||||||
/// protocol (described in RFC 959).
|
|
||||||
/// It provides easy access and transfers to remote
|
|
||||||
/// directories and files on a FTP server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API Ftp : NonCopyable
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Enumeration of transfer modes
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
enum TransferMode
|
|
||||||
{
|
|
||||||
Binary, ///< Binary mode (file is transfered as a sequence of bytes)
|
|
||||||
Ascii, ///< Text mode using ASCII encoding
|
|
||||||
Ebcdic ///< Text mode using EBCDIC encoding
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// This class wraps a FTP response, which is basically :
|
|
||||||
/// - a status code
|
|
||||||
/// - a message
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API Response
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Enumerate all the valid status codes returned in
|
|
||||||
/// a FTP response
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
enum Status
|
|
||||||
{
|
|
||||||
// 1xx: the requested action is being initiated,
|
|
||||||
// expect another reply before proceeding with a new command
|
|
||||||
RestartMarkerReply = 110, ///< Restart marker reply
|
|
||||||
ServiceReadySoon = 120, ///< Service ready in N minutes
|
|
||||||
DataConnectionAlreadyOpened = 125, ///< Data connection already opened, transfer starting
|
|
||||||
OpeningDataConnection = 150, ///< File status ok, about to open data connection
|
|
||||||
|
|
||||||
// 2xx: the requested action has been successfully completed
|
|
||||||
Ok = 200, ///< Command ok
|
|
||||||
PointlessCommand = 202, ///< Command not implemented
|
|
||||||
SystemStatus = 211, ///< System status, or system help reply
|
|
||||||
DirectoryStatus = 212, ///< Directory status
|
|
||||||
FileStatus = 213, ///< File status
|
|
||||||
HelpMessage = 214, ///< Help message
|
|
||||||
SystemType = 215, ///< NAME system type, where NAME is an official system name from the list in the Assigned Numbers document
|
|
||||||
ServiceReady = 220, ///< Service ready for new user
|
|
||||||
ClosingConnection = 221, ///< Service closing control connection
|
|
||||||
DataConnectionOpened = 225, ///< Data connection open, no transfer in progress
|
|
||||||
ClosingDataConnection = 226, ///< Closing data connection, requested file action successful
|
|
||||||
EnteringPassiveMode = 227, ///< Entering passive mode
|
|
||||||
LoggedIn = 230, ///< User logged in, proceed. Logged out if appropriate
|
|
||||||
FileActionOk = 250, ///< Requested file action ok
|
|
||||||
DirectoryOk = 257, ///< PATHNAME created
|
|
||||||
|
|
||||||
// 3xx: the command has been accepted, but the requested action
|
|
||||||
// is dormant, pending receipt of further information
|
|
||||||
NeedPassword = 331, ///< User name ok, need password
|
|
||||||
NeedAccountToLogIn = 332, ///< Need account for login
|
|
||||||
NeedInformation = 350, ///< Requested file action pending further information
|
|
||||||
|
|
||||||
// 4xx: the command was not accepted and the requested action did not take place,
|
|
||||||
// but the error condition is temporary and the action may be requested again
|
|
||||||
ServiceUnavailable = 421, ///< Service not available, closing control connection
|
|
||||||
DataConnectionUnavailable = 425, ///< Can't open data connection
|
|
||||||
TransferAborted = 426, ///< Connection closed, transfer aborted
|
|
||||||
FileActionAborted = 450, ///< Requested file action not taken
|
|
||||||
LocalError = 451, ///< Requested action aborted, local error in processing
|
|
||||||
InsufficientStorageSpace = 452, ///< Requested action not taken; insufficient storage space in system, file unavailable
|
|
||||||
|
|
||||||
// 5xx: the command was not accepted and
|
|
||||||
// the requested action did not take place
|
|
||||||
CommandUnknown = 500, ///< Syntax error, command unrecognized
|
|
||||||
ParametersUnknown = 501, ///< Syntax error in parameters or arguments
|
|
||||||
CommandNotImplemented = 502, ///< Command not implemented
|
|
||||||
BadCommandSequence = 503, ///< Bad sequence of commands
|
|
||||||
ParameterNotImplemented = 504, ///< Command not implemented for that parameter
|
|
||||||
NotLoggedIn = 530, ///< Not logged in
|
|
||||||
NeedAccountToStore = 532, ///< Need account for storing files
|
|
||||||
FileUnavailable = 550, ///< Requested action not taken, file unavailable
|
|
||||||
PageTypeUnknown = 551, ///< Requested action aborted, page type unknown
|
|
||||||
NotEnoughMemory = 552, ///< Requested file action aborted, exceeded storage allocation
|
|
||||||
FilenameNotAllowed = 553, ///< Requested action not taken, file name not allowed
|
|
||||||
|
|
||||||
// 10xx: SFML custom codes
|
|
||||||
InvalidResponse = 1000, ///< Response is not a valid FTP one
|
|
||||||
ConnectionFailed = 1001, ///< Connection with server failed
|
|
||||||
ConnectionClosed = 1002, ///< Connection with server closed
|
|
||||||
InvalidFile = 1003 ///< Invalid file to upload / download
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
///
|
|
||||||
/// \param Code : Response status code (InvalidResponse by default)
|
|
||||||
/// \param Message : Response message (empty by default)
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response(Status Code = InvalidResponse, const std::string& Message = "");
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Convenience function to check if the response status code
|
|
||||||
/// means a success
|
|
||||||
///
|
|
||||||
/// \return True if status is success (code < 400)
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IsOk() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the response status code
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Status GetStatus() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the full message contained in the response
|
|
||||||
///
|
|
||||||
/// \return The response message
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& GetMessage() const;
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Status myStatus; ///< Status code returned from the server
|
|
||||||
std::string myMessage; ///< Last message received from the server
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Specialization of FTP response returning a directory
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API DirectoryResponse : public Response
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
///
|
|
||||||
/// \param Resp : Source response
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
DirectoryResponse(Response Resp);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the directory returned in the response
|
|
||||||
///
|
|
||||||
/// \return Directory name
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& GetDirectory() const;
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::string myDirectory; ///< Directory extracted from the response message
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Specialization of FTP response returning a filename lisiting
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API ListingResponse : public Response
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
///
|
|
||||||
/// \param Resp : Source response
|
|
||||||
/// \param Data : Data containing the raw listing
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
ListingResponse(Response Resp, const std::vector<char>& Data);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the number of filenames in the listing
|
|
||||||
///
|
|
||||||
/// \return Total number of filenames
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::size_t GetCount() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the Index-th filename in the directory
|
|
||||||
///
|
|
||||||
/// \param Index : Index of the filename to get
|
|
||||||
///
|
|
||||||
/// \return Index-th filename
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& GetFilename(std::size_t Index) const;
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::vector<std::string> myFilenames; ///< Filenames extracted from the data
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Destructor -- close the connection with the server
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
~Ftp();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Connect to the specified FTP server
|
|
||||||
///
|
|
||||||
/// \param Server : FTP server to connect to
|
|
||||||
/// \param Port : Port used for connection (21 by default, standard FTP port)
|
|
||||||
/// \param Timeout : Maximum time to wait, in seconds (0 by default, means no timeout)
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response Connect(const IPAddress& Server, unsigned short Port = 21, float Timeout = 0.f);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Log in using anonymous account
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response Login();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Log in using a username and a password
|
|
||||||
///
|
|
||||||
/// \param UserName : User name
|
|
||||||
/// \param Password : Password
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response Login(const std::string& UserName, const std::string& Password);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Close the connection with FTP server
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response Disconnect();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a null command just to prevent from being disconnected
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response KeepAlive();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the current working directory
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
DirectoryResponse GetWorkingDirectory();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the contents of the given directory
|
|
||||||
/// (subdirectories and files)
|
|
||||||
///
|
|
||||||
/// \param Directory : Directory to list ("" by default, the current one)
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
ListingResponse GetDirectoryListing(const std::string& Directory = "");
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Change the current working directory
|
|
||||||
///
|
|
||||||
/// \param Directory : New directory, relative to the current one
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response ChangeDirectory(const std::string& Directory);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Go to the parent directory of the current one
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response ParentDirectory();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Create a new directory
|
|
||||||
///
|
|
||||||
/// \param Name : Name of the directory to create
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response MakeDirectory(const std::string& Name);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove an existing directory
|
|
||||||
///
|
|
||||||
/// \param Name : Name of the directory to remove
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response DeleteDirectory(const std::string& Name);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Rename a file
|
|
||||||
///
|
|
||||||
/// \param File : File to rename
|
|
||||||
/// \param NewName : New name
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response RenameFile(const std::string& File, const std::string& NewName);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove an existing file
|
|
||||||
///
|
|
||||||
/// \param Name : File to remove
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response DeleteFile(const std::string& Name);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Download a file from the server
|
|
||||||
///
|
|
||||||
/// \param DistantFile : Path of the distant file to download
|
|
||||||
/// \param DestPath : Where to put to file on the local computer
|
|
||||||
/// \param Mode : Transfer mode (binary by default)
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode = Binary);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Upload a file to the server
|
|
||||||
///
|
|
||||||
/// \param LocalFile : Path of the local file to upload
|
|
||||||
/// \param DestPath : Where to put to file on the server
|
|
||||||
/// \param Mode : Transfer mode (binary by default)
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode = Binary);
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a command to the FTP server
|
|
||||||
///
|
|
||||||
/// \param Command : Command to send
|
|
||||||
/// \param Parameter : Command parameter ("" by default)
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response SendCommand(const std::string& Command, const std::string& Parameter = "");
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive a response from the server
|
|
||||||
/// (usually after a command has been sent)
|
|
||||||
///
|
|
||||||
/// \return Server response to the request
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Response GetResponse();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Utility class for exchanging datas with the server
|
|
||||||
/// on the data channel
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class DataChannel;
|
|
||||||
|
|
||||||
friend class DataChannel;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketTCP myCommandSocket; ///< Socket holding the control connection with the server
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sf
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_FTP_HPP
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -28,9 +28,11 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/System/NonCopyable.hpp>
|
#include <SFML/Network/Export.hpp>
|
||||||
#include <SFML/Network/IPAddress.hpp>
|
#include <SFML/Network/IPAddress.hpp>
|
||||||
#include <SFML/Network/SocketTCP.hpp>
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
#include <SFML/System/NonCopyable.hpp>
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -38,25 +40,24 @@
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// This class provides methods for manipulating the HTTP
|
/// \brief A HTTP client
|
||||||
/// protocol (described in RFC 1945).
|
///
|
||||||
/// It can connect to a website, get its files, send requests, etc.
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API Http : NonCopyable
|
class SFML_NETWORK_API Http : NonCopyable
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// This class wraps an HTTP request, which is basically :
|
/// \brief Define a HTTP request
|
||||||
/// - a header with a method, a target URI, and a set of field/value pairs
|
///
|
||||||
/// - an optional body (for POST requests)
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API Request
|
class SFML_NETWORK_API Request
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Enumerate the available HTTP methods for a request
|
/// \brief Enumerate the available HTTP methods for a request
|
||||||
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
enum Method
|
enum Method
|
||||||
{
|
{
|
||||||
|
@ -66,83 +67,106 @@ public :
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
/// \brief Default constructor
|
||||||
///
|
///
|
||||||
/// \param RequestMethod : Method to use for the request (Get by default)
|
/// This constructor creates a GET request, with the root
|
||||||
/// \param URI : Target URI ("/" by default -- index page)
|
/// URI ("/") and an empty body.
|
||||||
/// \param Body : Content of the request's body (empty by default)
|
///
|
||||||
|
/// \param uri Target URI
|
||||||
|
/// \param method Method to use for the request
|
||||||
|
/// \param body Content of the request's body
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Request(Method RequestMethod = Get, const std::string& URI = "/", const std::string& Body = "");
|
Request(const std::string& uri = "/", Method method = Get, const std::string& body = "");
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the value of a field; the field is added if it doesn't exist
|
/// \brief Set the value of a field
|
||||||
///
|
///
|
||||||
/// \param Field : Name of the field to set (case-insensitive)
|
/// The field is created if it doesn't exist. The name of
|
||||||
/// \param Value : Value of the field
|
/// the field is case insensitive.
|
||||||
|
/// By default, a request doesn't contain any field (but the
|
||||||
|
/// mandatory fields are added later by the HTTP client when
|
||||||
|
/// sending the request).
|
||||||
|
///
|
||||||
|
/// \param field Name of the field to set
|
||||||
|
/// \param value Value of the field
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SetField(const std::string& Field, const std::string& Value);
|
void setField(const std::string& field, const std::string& value);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the request method.
|
/// \brief Set the request method
|
||||||
/// This parameter is Http::Request::Get by default
|
|
||||||
///
|
///
|
||||||
/// \param RequestMethod : Method to use for the request
|
/// See the Method enumeration for a complete list of all
|
||||||
|
/// the availale methods.
|
||||||
|
/// The method is Http::Request::Get by default.
|
||||||
|
///
|
||||||
|
/// \param method Method to use for the request
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SetMethod(Method RequestMethod);
|
void setMethod(Method method);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the target URI of the request.
|
/// \brief Set the requested URI
|
||||||
/// This parameter is "/" by default
|
|
||||||
///
|
///
|
||||||
/// \param URI : URI to request, local to the host
|
/// The URI is the resource (usually a web page or a file)
|
||||||
|
/// that you want to get or post.
|
||||||
|
/// The URI is "/" (the root page) by default.
|
||||||
|
///
|
||||||
|
/// \param uri URI to request, relative to the host
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SetURI(const std::string& URI);
|
void setUri(const std::string& uri);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the HTTP version of the request.
|
/// \brief Set the HTTP version for the request
|
||||||
/// This parameter is 1.0 by default
|
|
||||||
///
|
///
|
||||||
/// \param Major : Major version number
|
/// The HTTP version is 1.0 by default.
|
||||||
/// \param Minor : Minor version number
|
///
|
||||||
|
/// \param major Major HTTP version number
|
||||||
|
/// \param minor Minor HTTP version number
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SetHttpVersion(unsigned int Major, unsigned int Minor);
|
void setHttpVersion(unsigned int major, unsigned int minor);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the body of the request. This parameter is optional and
|
/// \brief Set the body of the request
|
||||||
/// makes sense only for POST requests.
|
|
||||||
/// This parameter is empty by default
|
|
||||||
///
|
///
|
||||||
/// \param Body : Content of the request body
|
/// The body of a request is optional and only makes sense
|
||||||
|
/// for POST requests. It is ignored for all other methods.
|
||||||
|
/// The body is empty by default.
|
||||||
|
///
|
||||||
|
/// \param body Content of the body
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SetBody(const std::string& Body);
|
void setBody(const std::string& body);
|
||||||
|
|
||||||
private :
|
private :
|
||||||
|
|
||||||
friend class Http;
|
friend class Http;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the string representation of the request header
|
/// \brief Prepare the final request to send to the server
|
||||||
///
|
///
|
||||||
/// \return String containing the request
|
/// This is used internally by Http before sending the
|
||||||
|
/// request to the web server.
|
||||||
|
///
|
||||||
|
/// \return String containing the request, ready to be sent
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::string ToString() const;
|
std::string prepare() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Check if the given field has been defined
|
/// \brief Check if the request defines a field
|
||||||
///
|
///
|
||||||
/// \param Field : Name of the field to check (case-insensitive)
|
/// This function uses case-insensitive comparisons.
|
||||||
///
|
///
|
||||||
/// \return True if the field exists
|
/// \param field Name of the field to test
|
||||||
|
///
|
||||||
|
/// \return True if the field exists, false otherwise
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool HasField(const std::string& Field) const;
|
bool hasField(const std::string& field) const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Types
|
// Types
|
||||||
|
@ -152,26 +176,25 @@ public :
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
FieldTable myFields; ///< Fields of the header
|
FieldTable m_fields; ///< Fields of the header associated to their value
|
||||||
Method myMethod; ///< Method to use for the request
|
Method m_method; ///< Method to use for the request
|
||||||
std::string myURI; ///< Target URI of the request
|
std::string m_uri; ///< Target URI of the request
|
||||||
unsigned int myMajorVersion; ///< Major HTTP version
|
unsigned int m_majorVersion; ///< Major HTTP version
|
||||||
unsigned int myMinorVersion; ///< Minor HTTP version
|
unsigned int m_minorVersion; ///< Minor HTTP version
|
||||||
std::string myBody; ///< Body of the request
|
std::string m_body; ///< Body of the request
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// This class wraps an HTTP response, which is basically :
|
/// \brief Define a HTTP response
|
||||||
/// - a header with a status code and a set of field/value pairs
|
///
|
||||||
/// - a body (the content of the requested resource)
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API Response
|
class SFML_NETWORK_API Response
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Enumerate all the valid status codes returned in
|
/// \brief Enumerate all the valid status codes for a response
|
||||||
/// a HTTP response
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
enum Status
|
enum Status
|
||||||
{
|
{
|
||||||
|
@ -179,7 +202,9 @@ public :
|
||||||
Ok = 200, ///< Most common code returned when operation was successful
|
Ok = 200, ///< Most common code returned when operation was successful
|
||||||
Created = 201, ///< The resource has successfully been created
|
Created = 201, ///< The resource has successfully been created
|
||||||
Accepted = 202, ///< The request has been accepted, but will be processed later by the server
|
Accepted = 202, ///< The request has been accepted, but will be processed later by the server
|
||||||
NoContent = 204, ///< Sent when the server didn't send any data in return
|
NoContent = 204, ///< The server didn't send any data in return
|
||||||
|
ResetContent = 205, ///< The server informs the client that it should clear the view (form) that caused the request to be sent
|
||||||
|
PartialContent = 206, ///< The server has sent a part of the resource, as a response to a partial GET request
|
||||||
|
|
||||||
// 3xx: redirection
|
// 3xx: redirection
|
||||||
MultipleChoices = 300, ///< The requested page can be accessed from several locations
|
MultipleChoices = 300, ///< The requested page can be accessed from several locations
|
||||||
|
@ -192,12 +217,15 @@ public :
|
||||||
Unauthorized = 401, ///< The requested page needs an authentification to be accessed
|
Unauthorized = 401, ///< The requested page needs an authentification to be accessed
|
||||||
Forbidden = 403, ///< The requested page cannot be accessed at all, even with authentification
|
Forbidden = 403, ///< The requested page cannot be accessed at all, even with authentification
|
||||||
NotFound = 404, ///< The requested page doesn't exist
|
NotFound = 404, ///< The requested page doesn't exist
|
||||||
|
RangeNotSatisfiable = 407, ///< The server can't satisfy the partial GET request (with a "Range" header field)
|
||||||
|
|
||||||
// 5xx: server error
|
// 5xx: server error
|
||||||
InternalServerError = 500, ///< The server encountered an unexpected error
|
InternalServerError = 500, ///< The server encountered an unexpected error
|
||||||
NotImplemented = 501, ///< The server doesn't implement a requested feature
|
NotImplemented = 501, ///< The server doesn't implement a requested feature
|
||||||
BadGateway = 502, ///< The gateway server has received an error from the source server
|
BadGateway = 502, ///< The gateway server has received an error from the source server
|
||||||
ServiceNotAvailable = 503, ///< The server is temporarily unavailable (overloaded, in maintenance, ...)
|
ServiceNotAvailable = 503, ///< The server is temporarily unavailable (overloaded, in maintenance, ...)
|
||||||
|
GatewayTimeout = 504, ///< The gateway server couldn't receive a response from the source server
|
||||||
|
VersionNotSupported = 505, ///< The server doesn't support the requested HTTP version
|
||||||
|
|
||||||
// 10xx: SFML custom codes
|
// 10xx: SFML custom codes
|
||||||
InvalidResponse = 1000, ///< Response is not a valid HTTP one
|
InvalidResponse = 1000, ///< Response is not a valid HTTP one
|
||||||
|
@ -205,68 +233,88 @@ public :
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Constructs an empty response.
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Response();
|
Response();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the value of a field
|
/// \brief Get the value of a field
|
||||||
///
|
///
|
||||||
/// \param Field : Name of the field to get (case-insensitive)
|
/// If the field \a field is not found in the response header,
|
||||||
|
/// the empty string is returned. This function uses
|
||||||
|
/// case-insensitive comparisons.
|
||||||
|
///
|
||||||
|
/// \param field Name of the field to get
|
||||||
///
|
///
|
||||||
/// \return Value of the field, or empty string if not found
|
/// \return Value of the field, or empty string if not found
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
const std::string& GetField(const std::string& Field) const;
|
const std::string& getField(const std::string& field) const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the header's status code
|
/// \brief Get the response status code
|
||||||
///
|
///
|
||||||
/// \return Header's status code
|
/// The status code should be the first thing to be checked
|
||||||
|
/// after receiving a response, it defines whether it is a
|
||||||
|
/// success, a failure or anything else (see the Status
|
||||||
|
/// enumeration).
|
||||||
|
///
|
||||||
|
/// \return Status code of the response
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Status GetStatus() const;
|
Status getStatus() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the major HTTP version number of the response
|
/// \brief Get the major HTTP version number of the response
|
||||||
///
|
///
|
||||||
/// \return Major version number
|
/// \return Major HTTP version number
|
||||||
|
///
|
||||||
|
/// \see getMinorHttpVersion
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
unsigned int GetMajorHttpVersion() const;
|
unsigned int getMajorHttpVersion() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the major HTTP version number of the response
|
/// \brief Get the minor HTTP version number of the response
|
||||||
///
|
///
|
||||||
/// \return Major version number
|
/// \return Minor HTTP version number
|
||||||
|
///
|
||||||
|
/// \see getMajorHttpVersion
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
unsigned int GetMinorHttpVersion() const;
|
unsigned int getMinorHttpVersion() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the body of the response. The body can contain :
|
/// \brief Get the body of the response
|
||||||
/// - the requested page (for GET requests)
|
///
|
||||||
/// - a response from the server (for POST requests)
|
/// The body of a response may contain:
|
||||||
/// - nothing (for HEAD requests)
|
/// \li the requested page (for GET requests)
|
||||||
/// - an error message (in case of an error)
|
/// \li a response from the server (for POST requests)
|
||||||
|
/// \li nothing (for HEAD requests)
|
||||||
|
/// \li an error message (in case of an error)
|
||||||
///
|
///
|
||||||
/// \return The response body
|
/// \return The response body
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
const std::string& GetBody() const;
|
const std::string& getBody() const;
|
||||||
|
|
||||||
private :
|
private :
|
||||||
|
|
||||||
friend class Http;
|
friend class Http;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the header from a response string
|
/// \brief Construct the header from a response string
|
||||||
///
|
///
|
||||||
/// \param Data : Content of the response's header to parse
|
/// This function is used by Http to build the response
|
||||||
|
/// of a request.
|
||||||
|
///
|
||||||
|
/// \param data Content of the response to parse
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void FromString(const std::string& Data);
|
void parse(const std::string& data);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Types
|
// Types
|
||||||
|
@ -276,65 +324,144 @@ public :
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
FieldTable myFields; ///< Fields of the header
|
FieldTable m_fields; ///< Fields of the header
|
||||||
Status myStatus; ///< Status code
|
Status m_status; ///< Status code
|
||||||
unsigned int myMajorVersion; ///< Major HTTP version
|
unsigned int m_majorVersion; ///< Major HTTP version
|
||||||
unsigned int myMinorVersion; ///< Minor HTTP version
|
unsigned int m_minorVersion; ///< Minor HTTP version
|
||||||
std::string myBody; ///< Body of the response
|
std::string m_body; ///< Body of the response
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
/// \brief Default constructor
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Http();
|
Http();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the Http instance with the target host
|
/// \brief Construct the HTTP client with the target host
|
||||||
///
|
///
|
||||||
/// \param Host : Web server to connect to
|
/// This is equivalent to calling setHost(host, port).
|
||||||
/// \param Port : Port to use for connection (0 by default -- use the standard port of the protocol used)
|
/// The port has a default value of 0, which means that the
|
||||||
|
/// HTTP client will use the right port according to the
|
||||||
|
/// protocol used (80 for HTTP, 443 for HTTPS). You should
|
||||||
|
/// leave it like this unless you really need a port other
|
||||||
|
/// than the standard one, or use an unknown protocol.
|
||||||
|
///
|
||||||
|
/// \param host Web server to connect to
|
||||||
|
/// \param port Port to use for connection
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Http(const std::string& Host, unsigned short Port = 0);
|
Http(const std::string& host, unsigned short port = 0);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the target host
|
/// \brief Set the target host
|
||||||
///
|
///
|
||||||
/// \param Host : Web server to connect to
|
/// This function just stores the host address and port, it
|
||||||
/// \param Port : Port to use for connection (0 by default -- use the standard port of the protocol used)
|
/// doesn't actually connect to it until you send a request.
|
||||||
|
/// The port has a default value of 0, which means that the
|
||||||
|
/// HTTP client will use the right port according to the
|
||||||
|
/// protocol used (80 for HTTP, 443 for HTTPS). You should
|
||||||
|
/// leave it like this unless you really need a port other
|
||||||
|
/// than the standard one, or use an unknown protocol.
|
||||||
|
///
|
||||||
|
/// \param host Web server to connect to
|
||||||
|
/// \param port Port to use for connection
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void SetHost(const std::string& Host, unsigned short Port = 0);
|
void setHost(const std::string& host, unsigned short port = 0);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Send a HTTP request and return the server's response.
|
/// \brief Send a HTTP request and return the server's response.
|
||||||
/// You must be connected to a host before sending requests.
|
///
|
||||||
/// Any missing mandatory header field will be added with an appropriate value.
|
/// You must have a valid host before sending a request (see setHost).
|
||||||
/// Warning : this function waits for the server's response and may
|
/// Any missing mandatory header field in the request will be added
|
||||||
|
/// with an appropriate value.
|
||||||
|
/// Warning: this function waits for the server's response and may
|
||||||
/// not return instantly; use a thread if you don't want to block your
|
/// not return instantly; use a thread if you don't want to block your
|
||||||
/// application.
|
/// application, or use a timeout to limit the time to wait. A value
|
||||||
|
/// of Time::Zero means that the client will use the system defaut timeout
|
||||||
|
/// (which is usually pretty long).
|
||||||
///
|
///
|
||||||
/// \param Req : Request to send
|
/// \param request Request to send
|
||||||
/// \param Timeout : Maximum time to wait, in seconds (0 by default, means no timeout)
|
/// \param timeout Maximum time to wait
|
||||||
///
|
///
|
||||||
/// \return Server's response
|
/// \return Server's response
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Response SendRequest(const Request& Req, float Timeout = 0.f);
|
Response sendRequest(const Request& request, Time timeout = Time::Zero);
|
||||||
|
|
||||||
private :
|
private :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
SocketTCP myConnection; ///< Connection to the host
|
TcpSocket m_connection; ///< Connection to the host
|
||||||
IPAddress myHost; ///< Web host address
|
IpAddress m_host; ///< Web host address
|
||||||
std::string myHostName; ///< Web host name
|
std::string m_hostName; ///< Web host name
|
||||||
unsigned short myPort; ///< Port used for connection with host
|
unsigned short m_port; ///< Port used for connection with host
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_HTTP_HPP
|
#endif // SFML_HTTP_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Http
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// sf::Http is a very simple HTTP client that allows you
|
||||||
|
/// to communicate with a web server. You can retrieve
|
||||||
|
/// web pages, send data to an interactive resource,
|
||||||
|
/// download a remote file, etc.
|
||||||
|
///
|
||||||
|
/// The HTTP client is split into 3 classes:
|
||||||
|
/// \li sf::Http::Request
|
||||||
|
/// \li sf::Http::Response
|
||||||
|
/// \li sf::Http
|
||||||
|
///
|
||||||
|
/// sf::Http::Request builds the request that will be
|
||||||
|
/// sent to the server. A request is made of:
|
||||||
|
/// \li a method (what you want to do)
|
||||||
|
/// \li a target URI (usually the name of the web page or file)
|
||||||
|
/// \li one or more header fields (options that you can pass to the server)
|
||||||
|
/// \li an optional body (for POST requests)
|
||||||
|
///
|
||||||
|
/// sf::Http::Response parse the response from the web server
|
||||||
|
/// and provides getters to read them. The response contains:
|
||||||
|
/// \li a status code
|
||||||
|
/// \li header fields (that may be answers to the ones that you requested)
|
||||||
|
/// \li a body, which contains the contents of the requested resource
|
||||||
|
///
|
||||||
|
/// sf::Http provides a simple function, SendRequest, to send a
|
||||||
|
/// sf::Http::Request and return the corresponding sf::Http::Response
|
||||||
|
/// from the server.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a new HTTP client
|
||||||
|
/// sf::Http http;
|
||||||
|
///
|
||||||
|
/// // We'll work on http://www.sfml-dev.org
|
||||||
|
/// http.setHost("http://www.sfml-dev.org");
|
||||||
|
///
|
||||||
|
/// // Prepare a request to get the 'features.php' page
|
||||||
|
/// sf::Http::Request request("features.php");
|
||||||
|
///
|
||||||
|
/// // Send the request
|
||||||
|
/// sf::Http::Response response = http.sendRequest(request);
|
||||||
|
///
|
||||||
|
/// // Check the status code and display the result
|
||||||
|
/// sf::Http::Response::Status status = response.getStatus();
|
||||||
|
/// if (status == sf::Http::Response::Ok)
|
||||||
|
/// {
|
||||||
|
/// std::cout << response.getBody() << std::endl;
|
||||||
|
/// }
|
||||||
|
/// else
|
||||||
|
/// {
|
||||||
|
/// std::cout << "Error " << status << std::endl;
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -28,7 +28,8 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Config.hpp>
|
#include <SFML/Network/Export.hpp>
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -37,195 +38,279 @@
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// IPAddress provides easy manipulation of IP v4 addresses
|
/// \brief Encapsulate an IPv4 network address
|
||||||
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API IPAddress
|
class SFML_NETWORK_API IpAddress
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor -- constructs an invalid address
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor creates an empty (invalid) address
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
IPAddress();
|
IpAddress();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from a string
|
/// \brief Construct the address from a string
|
||||||
///
|
///
|
||||||
/// \param Address : IP address ("xxx.xxx.xxx.xxx") or network name
|
/// Here \a address can be either a decimal address
|
||||||
|
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
|
||||||
|
///
|
||||||
|
/// \param address IP address or network name
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
IPAddress(const std::string& Address);
|
IpAddress(const std::string& address);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from a C-style string ;
|
/// \brief Construct the address from a string
|
||||||
/// Needed for implicit conversions from literal strings to IPAddress to work
|
|
||||||
///
|
///
|
||||||
/// \param Address : IP address ("xxx.xxx.xxx.xxx") or network name
|
/// Here \a address can be either a decimal address
|
||||||
|
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
|
||||||
|
/// This is equivalent to the constructor taking a std::string
|
||||||
|
/// parameter, it is defined for convenience so that the
|
||||||
|
/// implicit conversions from literal strings to IpAddress work.
|
||||||
|
///
|
||||||
|
/// \param address IP address or network name
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
IPAddress(const char* Address);
|
IpAddress(const char* address);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from 4 bytes
|
/// \brief Construct the address from 4 bytes
|
||||||
///
|
///
|
||||||
/// \param Byte0 : First byte of the address
|
/// Calling IpAddress(a, b, c, d) is equivalent to calling
|
||||||
/// \param Byte1 : Second byte of the address
|
/// IpAddress("a.b.c.d"), but safer as it doesn't have to
|
||||||
/// \param Byte2 : Third byte of the address
|
/// parse a string to get the address components.
|
||||||
/// \param Byte3 : Fourth byte of the address
|
///
|
||||||
|
/// \param byte0 First byte of the address
|
||||||
|
/// \param byte1 Second byte of the address
|
||||||
|
/// \param byte2 Third byte of the address
|
||||||
|
/// \param byte3 Fourth byte of the address
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3);
|
IpAddress(Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from a 32-bits integer
|
/// \brief Construct the address from a 32-bits integer
|
||||||
///
|
///
|
||||||
/// \param Address : 4 bytes of the address packed into a 32-bits integer
|
/// This constructor uses the internal representation of
|
||||||
|
/// the address directly. It should be used for optimization
|
||||||
|
/// purposes, and only if you got that representation from
|
||||||
|
/// IpAddress::ToInteger().
|
||||||
|
///
|
||||||
|
/// \param address 4 bytes of the address packed into a 32-bits integer
|
||||||
|
///
|
||||||
|
/// \see toInteger
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
IPAddress(Uint32 Address);
|
explicit IpAddress(Uint32 address);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Tell if the address is a valid one
|
/// \brief Get a string representation of the address
|
||||||
///
|
///
|
||||||
/// \return True if address has a valid syntax
|
/// The returned string is the decimal representation of the
|
||||||
|
/// IP address (like "192.168.1.56"), even if it was constructed
|
||||||
|
/// from a host name.
|
||||||
|
///
|
||||||
|
/// \return String representation of the address
|
||||||
|
///
|
||||||
|
/// \see toInteger
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool IsValid() const;
|
std::string toString() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get a string representation of the address
|
/// \brief Get an integer representation of the address
|
||||||
///
|
///
|
||||||
/// \return String representation of the IP address ("xxx.xxx.xxx.xxx")
|
/// The returned number is the internal representation of the
|
||||||
|
/// address, and should be used for optimization purposes only
|
||||||
|
/// (like sending the address through a socket).
|
||||||
|
/// The integer produced by this function can then be converted
|
||||||
|
/// back to a sf::IpAddress with the proper constructor.
|
||||||
|
///
|
||||||
|
/// \return 32-bits unsigned integer representation of the address
|
||||||
|
///
|
||||||
|
/// \see toString
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::string ToString() const;
|
Uint32 toInteger() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get an integer representation of the address
|
/// \brief Get the computer's local address
|
||||||
///
|
///
|
||||||
/// \return 32-bits integer containing the 4 bytes of the address, in system endianness
|
/// The local address is the address of the computer from the
|
||||||
|
/// LAN point of view, i.e. something like 192.168.1.56. It is
|
||||||
|
/// meaningful only for communications over the local network.
|
||||||
|
/// Unlike getPublicAddress, this function is fast and may be
|
||||||
|
/// used safely anywhere.
|
||||||
|
///
|
||||||
|
/// \return Local IP address of the computer
|
||||||
|
///
|
||||||
|
/// \see getPublicAddress
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Uint32 ToInteger() const;
|
static IpAddress getLocalAddress();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the computer's local IP address (from the LAN point of view)
|
/// \brief Get the computer's public address
|
||||||
///
|
///
|
||||||
/// \return Local IP address
|
/// The public address is the address of the computer from the
|
||||||
///
|
/// internet point of view, i.e. something like 89.54.1.169.
|
||||||
////////////////////////////////////////////////////////////
|
/// It is necessary for communications over the world wide web.
|
||||||
static IPAddress GetLocalAddress();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the computer's public IP address (from the web point of view).
|
|
||||||
/// The only way to get a public address is to ask it to a
|
/// The only way to get a public address is to ask it to a
|
||||||
/// distant website ; as a consequence, this function may be
|
/// distant website; as a consequence, this function depends on
|
||||||
/// very slow -- use it as few as possible !
|
/// both your network connection and the server, and may be
|
||||||
|
/// very slow. You should use it as few as possible. Because
|
||||||
|
/// this function depends on the network connection and on a distant
|
||||||
|
/// server, you may use a time limit if you don't want your program
|
||||||
|
/// to be possibly stuck waiting in case there is a problem; this
|
||||||
|
/// limit is deactivated by default.
|
||||||
///
|
///
|
||||||
/// \param Timeout : Maximum time to wait, in seconds (0 by default : no timeout)
|
/// \param timeout Maximum time to wait
|
||||||
///
|
///
|
||||||
/// \return Public IP address
|
/// \return Public IP address of the computer
|
||||||
|
///
|
||||||
|
/// \see getLocalAddress
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static IPAddress GetPublicAddress(float Timeout = 0.f);
|
static IpAddress getPublicAddress(Time timeout = Time::Zero);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator ==
|
|
||||||
///
|
|
||||||
/// \param Other : Address to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this == Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator ==(const IPAddress& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator !=
|
|
||||||
///
|
|
||||||
/// \param Other : Address to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this != Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator !=(const IPAddress& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator <
|
|
||||||
///
|
|
||||||
/// \param Other : Address to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this < Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator <(const IPAddress& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator >
|
|
||||||
///
|
|
||||||
/// \param Other : Address to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this > Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator >(const IPAddress& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator <=
|
|
||||||
///
|
|
||||||
/// \param Other : Address to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this <= Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator <=(const IPAddress& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator >=
|
|
||||||
///
|
|
||||||
/// \param Other : Address to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this >= Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator >=(const IPAddress& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Static member data
|
// Static member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static const IPAddress LocalHost; ///< Local host address (to connect to the same computer)
|
static const IpAddress None; ///< Value representing an empty/invalid address
|
||||||
|
static const IpAddress LocalHost; ///< The "localhost" address (for connecting a computer to itself locally)
|
||||||
|
static const IpAddress Broadcast; ///< The "broadcast" address (for sending UDP messages to everyone on a local network)
|
||||||
|
|
||||||
private :
|
private :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Uint32 myAddress; ///< Address stored as an unsigned 32 bits integer
|
Uint32 m_address; ///< Address stored as an unsigned 32 bits integer
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator >> overload to extract an address from an input stream
|
/// \brief Overload of == operator to compare two IP addresses
|
||||||
///
|
///
|
||||||
/// \param Stream : Input stream
|
/// \param left Left operand (a IP address)
|
||||||
/// \param Address : Address to extract
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return True if both addresses are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API bool operator ==(const IpAddress& left, const IpAddress& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of != operator to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return True if both addresses are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API bool operator !=(const IpAddress& left, const IpAddress& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of < operator to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is lesser than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API bool operator <(const IpAddress& left, const IpAddress& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of > operator to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is greater than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API bool operator >(const IpAddress& left, const IpAddress& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of <= operator to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is lesser or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API bool operator <=(const IpAddress& left, const IpAddress& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of >= operator to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is greater or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API bool operator >=(const IpAddress& left, const IpAddress& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of >> operator to extract an IP address from an input stream
|
||||||
|
///
|
||||||
|
/// \param stream Input stream
|
||||||
|
/// \param address IP address to extract
|
||||||
///
|
///
|
||||||
/// \return Reference to the input stream
|
/// \return Reference to the input stream
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
SFML_API std::istream& operator >>(std::istream& Stream, IPAddress& Address);
|
SFML_NETWORK_API std::istream& operator >>(std::istream& stream, IpAddress& address);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator << overload to print an address to an output stream
|
/// \brief Overload of << operator to print an IP address to an output stream
|
||||||
///
|
///
|
||||||
/// \param Stream : Output stream
|
/// \param stream Output stream
|
||||||
/// \param Address : Address to print
|
/// \param address IP address to print
|
||||||
///
|
///
|
||||||
/// \return Reference to the output stream
|
/// \return Reference to the output stream
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
SFML_API std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address);
|
SFML_NETWORK_API std::ostream& operator <<(std::ostream& stream, const IpAddress& address);
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_IPADDRESS_HPP
|
#endif // SFML_IPADDRESS_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::IpAddress
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// sf::IpAddress is a utility class for manipulating network
|
||||||
|
/// addresses. It provides a set a implicit constructors and
|
||||||
|
/// conversion functions to easily build or transform an IP
|
||||||
|
/// address from/to various representations.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::IpAddress a0; // an invalid address
|
||||||
|
/// sf::IpAddress a1 = sf::IpAddress::None; // an invalid address (same as a0)
|
||||||
|
/// sf::IpAddress a2("127.0.0.1"); // the local host address
|
||||||
|
/// sf::IpAddress a3 = sf::IpAddress::Broadcast; // the broadcast address
|
||||||
|
/// sf::IpAddress a4(192, 168, 1, 56); // a local address
|
||||||
|
/// sf::IpAddress a5("my_computer"); // a local address created from a network name
|
||||||
|
/// sf::IpAddress a6("89.54.1.169"); // a distant address
|
||||||
|
/// sf::IpAddress a7("www.google.com"); // a distant address created from a network name
|
||||||
|
/// sf::IpAddress a8 = sf::IpAddress::getLocalAddress(); // my address on the local network
|
||||||
|
/// sf::IpAddress a9 = sf::IpAddress::getPublicAddress(); // my address on the internet
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Note that sf::IpAddress currently doesn't support IPv6
|
||||||
|
/// nor other types of network addresses.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -28,160 +28,380 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Config.hpp>
|
#include <SFML/Network/Export.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
class String;
|
||||||
|
class TcpSocket;
|
||||||
|
class UdpSocket;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Packet wraps data to send / to receive through the network
|
/// \brief Utility class to build blocks of data to transfer
|
||||||
|
/// over the network
|
||||||
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API Packet
|
class SFML_NETWORK_API Packet
|
||||||
{
|
{
|
||||||
|
// A bool-like type that cannot be converted to integer or pointer types
|
||||||
|
typedef bool (Packet::*BoolType)(std::size_t);
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates an empty packet.
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Packet();
|
Packet();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Virtual destructor
|
/// \brief Virtual destructor
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual ~Packet();
|
virtual ~Packet();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Append data to the end of the packet
|
/// \brief Append data to the end of the packet
|
||||||
///
|
///
|
||||||
/// \param Data : Pointer to the bytes to append
|
/// \param data Pointer to the sequence of bytes to append
|
||||||
/// \param SizeInBytes : Number of bytes to append
|
/// \param sizeInBytes Number of bytes to append
|
||||||
|
///
|
||||||
|
/// \see clear
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Append(const void* Data, std::size_t SizeInBytes);
|
void append(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Clear the packet data
|
/// \brief Clear the packet
|
||||||
|
///
|
||||||
|
/// After calling Clear, the packet is empty.
|
||||||
|
///
|
||||||
|
/// \see append
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Clear();
|
void clear();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get a pointer to the data contained in the packet
|
/// \brief Get a pointer to the data contained in the packet
|
||||||
/// Warning : the returned pointer may be invalid after you
|
///
|
||||||
/// append data to the packet
|
/// Warning: the returned pointer may become invalid after
|
||||||
|
/// you append data to the packet, therefore it should never
|
||||||
|
/// be stored.
|
||||||
|
/// The return pointer is NULL if the packet is empty.
|
||||||
///
|
///
|
||||||
/// \return Pointer to the data
|
/// \return Pointer to the data
|
||||||
///
|
///
|
||||||
|
/// \see getDataSize
|
||||||
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
const char* GetData() const;
|
const void* getData() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the size of the data contained in the packet
|
/// \brief Get the size of the data contained in the packet
|
||||||
|
///
|
||||||
|
/// This function returns the number of bytes pointed to by
|
||||||
|
/// what getData returns.
|
||||||
///
|
///
|
||||||
/// \return Data size, in bytes
|
/// \return Data size, in bytes
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
/// \see getData
|
||||||
std::size_t GetDataSize() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Tell if the reading position has reached the end of the packet
|
|
||||||
///
|
|
||||||
/// \return True if all data have been read into the packet
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool EndOfPacket() const;
|
std::size_t getDataSize() const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Return the validity of packet
|
/// \brief Tell if the reading position has reached the
|
||||||
|
/// end of the packet
|
||||||
|
///
|
||||||
|
/// This function is useful to know if there is some data
|
||||||
|
/// left to be read, without actually reading it.
|
||||||
|
///
|
||||||
|
/// \return True if all data was read, false otherwise
|
||||||
|
///
|
||||||
|
/// \see operator bool
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool endOfPacket() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Test the validity of the packet, for reading
|
||||||
|
///
|
||||||
|
/// This operator allows to test the packet as a boolean
|
||||||
|
/// variable, to check if a reading operation was successful.
|
||||||
|
///
|
||||||
|
/// A packet will be in an invalid state if it has no more
|
||||||
|
/// data to read.
|
||||||
|
///
|
||||||
|
/// This behaviour is the same as standard C++ streams.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// float x;
|
||||||
|
/// packet >> x;
|
||||||
|
/// if (packet)
|
||||||
|
/// {
|
||||||
|
/// // ok, x was extracted successfully
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // -- or --
|
||||||
|
///
|
||||||
|
/// float x;
|
||||||
|
/// if (packet >> x)
|
||||||
|
/// {
|
||||||
|
/// // ok, x was extracted successfully
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Don't focus on the return type, it's equivalent to bool but
|
||||||
|
/// it disallows unwanted implicit conversions to integer or
|
||||||
|
/// pointer types.
|
||||||
///
|
///
|
||||||
/// \return True if last data extraction from packet was successful
|
/// \return True if last data extraction from packet was successful
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
/// \see endOfPacket
|
||||||
operator bool() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Operator >> overloads to extract data from the packet
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Packet& operator >>(bool& Data);
|
operator BoolType() const;
|
||||||
Packet& operator >>(Int8& Data);
|
|
||||||
Packet& operator >>(Uint8& Data);
|
|
||||||
Packet& operator >>(Int16& Data);
|
|
||||||
Packet& operator >>(Uint16& Data);
|
|
||||||
Packet& operator >>(Int32& Data);
|
|
||||||
Packet& operator >>(Uint32& Data);
|
|
||||||
Packet& operator >>(float& Data);
|
|
||||||
Packet& operator >>(double& Data);
|
|
||||||
Packet& operator >>(char* Data);
|
|
||||||
Packet& operator >>(std::string& Data);
|
|
||||||
Packet& operator >>(wchar_t* Data);
|
|
||||||
Packet& operator >>(std::wstring& Data);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator << overloads to put data into the packet
|
/// Overloads of operator >> to read data from the packet
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Packet& operator <<(bool Data);
|
Packet& operator >>(bool& data);
|
||||||
Packet& operator <<(Int8 Data);
|
Packet& operator >>(Int8& data);
|
||||||
Packet& operator <<(Uint8 Data);
|
Packet& operator >>(Uint8& data);
|
||||||
Packet& operator <<(Int16 Data);
|
Packet& operator >>(Int16& data);
|
||||||
Packet& operator <<(Uint16 Data);
|
Packet& operator >>(Uint16& data);
|
||||||
Packet& operator <<(Int32 Data);
|
Packet& operator >>(Int32& data);
|
||||||
Packet& operator <<(Uint32 Data);
|
Packet& operator >>(Uint32& data);
|
||||||
Packet& operator <<(float Data);
|
Packet& operator >>(float& data);
|
||||||
Packet& operator <<(double Data);
|
Packet& operator >>(double& data);
|
||||||
Packet& operator <<(const char* Data);
|
Packet& operator >>(char* data);
|
||||||
Packet& operator <<(const std::string& Data);
|
Packet& operator >>(std::string& data);
|
||||||
Packet& operator <<(const wchar_t* Data);
|
Packet& operator >>(wchar_t* data);
|
||||||
Packet& operator <<(const std::wstring& Data);
|
Packet& operator >>(std::wstring& data);
|
||||||
|
Packet& operator >>(String& data);
|
||||||
private :
|
|
||||||
|
|
||||||
friend class SocketTCP;
|
|
||||||
friend class SocketUDP;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Check if the packet can extract a given size of bytes
|
/// Overloads of operator << to write data into the packet
|
||||||
///
|
|
||||||
/// \param Size : Size to check
|
|
||||||
///
|
|
||||||
/// \return True if Size bytes can be read from the packet's data
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool CheckSize(std::size_t Size);
|
Packet& operator <<(bool data);
|
||||||
|
Packet& operator <<(Int8 data);
|
||||||
|
Packet& operator <<(Uint8 data);
|
||||||
|
Packet& operator <<(Int16 data);
|
||||||
|
Packet& operator <<(Uint16 data);
|
||||||
|
Packet& operator <<(Int32 data);
|
||||||
|
Packet& operator <<(Uint32 data);
|
||||||
|
Packet& operator <<(float data);
|
||||||
|
Packet& operator <<(double data);
|
||||||
|
Packet& operator <<(const char* data);
|
||||||
|
Packet& operator <<(const std::string& data);
|
||||||
|
Packet& operator <<(const wchar_t* data);
|
||||||
|
Packet& operator <<(const std::wstring& data);
|
||||||
|
Packet& operator <<(const String& data);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
friend class TcpSocket;
|
||||||
|
friend class UdpSocket;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Called before the packet is sent to the network
|
/// \brief Called before the packet is sent over the network
|
||||||
///
|
///
|
||||||
/// \param DataSize : Variable to fill with the size of data to send
|
/// This function can be defined by derived classes to
|
||||||
|
/// transform the data before it is sent; this can be
|
||||||
|
/// used for compression, encryption, etc.
|
||||||
|
/// The function must return a pointer to the modified data,
|
||||||
|
/// as well as the number of bytes pointed.
|
||||||
|
/// The default implementation provides the packet's data
|
||||||
|
/// without transforming it.
|
||||||
|
///
|
||||||
|
/// \param size Variable to fill with the size of data to send
|
||||||
///
|
///
|
||||||
/// \return Pointer to the array of bytes to send
|
/// \return Pointer to the array of bytes to send
|
||||||
///
|
///
|
||||||
|
/// \see onReceive
|
||||||
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual const char* OnSend(std::size_t& DataSize);
|
virtual const void* onSend(std::size_t& size);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Called after the packet has been received from the network
|
/// \brief Called after the packet is received over the network
|
||||||
///
|
///
|
||||||
/// \param Data : Pointer to the array of received bytes
|
/// This function can be defined by derived classes to
|
||||||
/// \param DataSize : Size of the array of bytes
|
/// transform the data after it is received; this can be
|
||||||
|
/// used for uncompression, decryption, etc.
|
||||||
|
/// The function receives a pointer to the received data,
|
||||||
|
/// and must fill the packet with the transformed bytes.
|
||||||
|
/// The default implementation fills the packet directly
|
||||||
|
/// without transforming the data.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the received bytes
|
||||||
|
/// \param size Number of bytes
|
||||||
|
///
|
||||||
|
/// \see onSend
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual void OnReceive(const char* Data, std::size_t DataSize);
|
virtual void onReceive(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// Disallow comparisons between packets
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator ==(const Packet& right) const;
|
||||||
|
bool operator !=(const Packet& right) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if the packet can extract a given number of bytes
|
||||||
|
///
|
||||||
|
/// This function updates accordingly the state of the packet.
|
||||||
|
///
|
||||||
|
/// \param size Size to check
|
||||||
|
///
|
||||||
|
/// \return True if \a size bytes can be read from the packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool checkSize(std::size_t size);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::vector<char> myData; ///< Data stored in the packet
|
std::vector<char> m_data; ///< Data stored in the packet
|
||||||
std::size_t myReadPos; ///< Current reading position in the packet
|
std::size_t m_readPos; ///< Current reading position in the packet
|
||||||
bool myIsValid; ///< Reading state of the packet
|
bool m_isValid; ///< Reading state of the packet
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_PACKET_HPP
|
#endif // SFML_PACKET_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Packet
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// Packets provide a safe and easy way to serialize data,
|
||||||
|
/// in order to send it over the network using sockets
|
||||||
|
/// (sf::TcpSocket, sf::UdpSocket).
|
||||||
|
///
|
||||||
|
/// Packets solve 2 fundamental problems that arise when
|
||||||
|
/// transfering data over the network:
|
||||||
|
/// \li data is interpreted correctly according to the endianness
|
||||||
|
/// \li the bounds of the packet are preserved (one send == one receive)
|
||||||
|
///
|
||||||
|
/// The sf::Packet class provides both input and output modes.
|
||||||
|
/// It is designed to follow the behaviour of standard C++ streams,
|
||||||
|
/// using operators >> and << to extract and insert data.
|
||||||
|
///
|
||||||
|
/// It is recommended to use only fixed-size types (like sf::Int32, etc.),
|
||||||
|
/// to avoid possible differences between the sender and the receiver.
|
||||||
|
/// Indeed, the native C++ types may have different sizes on two platforms
|
||||||
|
/// and your data may be corrupted if that happens.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::Uint32 x = 24;
|
||||||
|
/// std::string s = "hello";
|
||||||
|
/// double d = 5.89;
|
||||||
|
///
|
||||||
|
/// // Group the variables to send into a packet
|
||||||
|
/// sf::Packet packet;
|
||||||
|
/// packet << x << s << d;
|
||||||
|
///
|
||||||
|
/// // Send it over the network (socket is a valid sf::TcpSocket)
|
||||||
|
/// socket.send(packet);
|
||||||
|
///
|
||||||
|
/// -----------------------------------------------------------------
|
||||||
|
///
|
||||||
|
/// // Receive the packet at the other end
|
||||||
|
/// sf::Packet packet;
|
||||||
|
/// socket.receive(packet);
|
||||||
|
///
|
||||||
|
/// // Extract the variables contained in the packet
|
||||||
|
/// sf::Uint32 x;
|
||||||
|
/// std::string s;
|
||||||
|
/// double d;
|
||||||
|
/// if (packet >> x >> s >> d)
|
||||||
|
/// {
|
||||||
|
/// // Data extracted successfully...
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Packets have built-in operator >> and << overloads for
|
||||||
|
/// standard types:
|
||||||
|
/// \li bool
|
||||||
|
/// \li fixed-size integer types (sf::Int8/16/32, sf::Uint8/16/32)
|
||||||
|
/// \li floating point numbers (float, double)
|
||||||
|
/// \li string types (char*, wchar_t*, std::string, std::wstring, sf::String)
|
||||||
|
///
|
||||||
|
/// Like standard streams, it is also possible to define your own
|
||||||
|
/// overloads of operators >> and << in order to handle your
|
||||||
|
/// custom types.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// struct MyStruct
|
||||||
|
/// {
|
||||||
|
/// float number;
|
||||||
|
/// sf::Int8 integer;
|
||||||
|
/// std::string str;
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// sf::Packet& operator <<(sf::Packet& packet, const MyStruct& m)
|
||||||
|
/// {
|
||||||
|
/// return packet << m.number << m.integer << m.str;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// sf::Packet& operator >>(sf::Packet& packet, MyStruct& m)
|
||||||
|
/// {
|
||||||
|
/// return packet >> m.number >> m.integer >> m.str;
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Packets also provide an extra feature that allows to apply
|
||||||
|
/// custom transformations to the data before it is sent,
|
||||||
|
/// and after it is received. This is typically used to
|
||||||
|
/// handle automatic compression or encryption of the data.
|
||||||
|
/// This is achieved by inheriting from sf::Packet, and overriding
|
||||||
|
/// the onSend and onReceive functions.
|
||||||
|
///
|
||||||
|
/// Here is an example:
|
||||||
|
/// \code
|
||||||
|
/// class ZipPacket : public sf::Packet
|
||||||
|
/// {
|
||||||
|
/// virtual const void* onSend(std::size_t& size)
|
||||||
|
/// {
|
||||||
|
/// const void* srcData = getData();
|
||||||
|
/// std::size_t srcSize = getDataSize();
|
||||||
|
///
|
||||||
|
/// return MySuperZipFunction(srcData, srcSize, &size);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// virtual void onReceive(const void* data, std::size_t size)
|
||||||
|
/// {
|
||||||
|
/// std::size_t dstSize;
|
||||||
|
/// const void* dstData = MySuperUnzipFunction(data, size, &dstSize);
|
||||||
|
///
|
||||||
|
/// append(dstData, dstSize);
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Use like regular packets:
|
||||||
|
/// ZipPacket packet;
|
||||||
|
/// packet << x << s << d;
|
||||||
|
/// ...
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see sf::TcpSocket, sf::UdpSocket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef SFML_SELECTOR_HPP
|
|
||||||
#define SFML_SELECTOR_HPP
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/SocketUDP.hpp>
|
|
||||||
#include <SFML/Network/SocketTCP.hpp>
|
|
||||||
#include <SFML/Network/SelectorBase.hpp>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Selector allow reading from multiple sockets
|
|
||||||
/// without blocking. It's a kind of multiplexer
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
template <typename Type>
|
|
||||||
class Selector : private SelectorBase
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Add a socket to watch
|
|
||||||
///
|
|
||||||
/// \param Socket : Socket to add
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Add(Type Socket);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove a socket
|
|
||||||
///
|
|
||||||
/// \param Socket : Socket to remove
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Remove(Type Socket);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove all sockets
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Wait and collect sockets which are ready for reading.
|
|
||||||
/// This functions will return either when at least one socket
|
|
||||||
/// is ready, or when the given time is out
|
|
||||||
///
|
|
||||||
/// \param Timeout : Timeout, in seconds (0 by default : no timeout)
|
|
||||||
///
|
|
||||||
/// \return Number of sockets ready to be read
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned int Wait(float Timeout = 0.f);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// After a call to Wait(), get the Index-th socket which is
|
|
||||||
/// ready for reading. The total number of sockets ready
|
|
||||||
/// is the integer returned by the previous call to Wait()
|
|
||||||
///
|
|
||||||
/// \param Index : Index of the socket to get
|
|
||||||
///
|
|
||||||
/// \return The Index-th socket
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Type GetSocketReady(unsigned int Index);
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Types
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
typedef std::map<SocketHelper::SocketType, Type> SocketTable;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketTable mySockets; ///< Table matching the SFML socket instances with their low-level handles
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <SFML/Network/Selector.inl>
|
|
||||||
|
|
||||||
// Let's define the two only valid types of Selector
|
|
||||||
typedef Selector<SocketUDP> SelectorUDP;
|
|
||||||
typedef Selector<SocketTCP> SelectorTCP;
|
|
||||||
|
|
||||||
} // namespace sf
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SELECTOR_HPP
|
|
|
@ -1,97 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Add a socket to watch
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
template <typename Type>
|
|
||||||
void Selector<Type>::Add(Type Socket)
|
|
||||||
{
|
|
||||||
if (Socket.IsValid())
|
|
||||||
{
|
|
||||||
SelectorBase::Add(Socket.mySocket);
|
|
||||||
mySockets[Socket.mySocket] = Socket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove a socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
template <typename Type>
|
|
||||||
void Selector<Type>::Remove(Type Socket)
|
|
||||||
{
|
|
||||||
typename SocketTable::iterator It = mySockets.find(Socket.mySocket);
|
|
||||||
if (It != mySockets.end())
|
|
||||||
{
|
|
||||||
SelectorBase::Remove(Socket.mySocket);
|
|
||||||
mySockets.erase(It);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove all sockets
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
template <typename Type>
|
|
||||||
void Selector<Type>::Clear()
|
|
||||||
{
|
|
||||||
SelectorBase::Clear();
|
|
||||||
mySockets.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Wait and collect sockets which are ready for reading.
|
|
||||||
/// This functions will return either when at least one socket
|
|
||||||
/// is ready, or when the given time is out
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
template <typename Type>
|
|
||||||
unsigned int Selector<Type>::Wait(float Timeout)
|
|
||||||
{
|
|
||||||
// No socket in the selector : return 0
|
|
||||||
if (mySockets.empty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return SelectorBase::Wait(Timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// After a call to Wait(), get the Index-th socket which is
|
|
||||||
/// ready for reading. The total number of sockets ready
|
|
||||||
/// is the integer returned by the previous call to Wait()
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
template <typename Type>
|
|
||||||
Type Selector<Type>::GetSocketReady(unsigned int Index)
|
|
||||||
{
|
|
||||||
SocketHelper::SocketType Socket = SelectorBase::GetSocketReady(Index);
|
|
||||||
|
|
||||||
typename SocketTable::const_iterator It = mySockets.find(Socket);
|
|
||||||
if (It != mySockets.end())
|
|
||||||
return It->second;
|
|
||||||
else
|
|
||||||
return Type(Socket);
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef SFML_SELECTORBASE_HPP
|
|
||||||
#define SFML_SELECTORBASE_HPP
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Config.hpp>
|
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Private base class for selectors.
|
|
||||||
/// As Selector is a template class, this base is needed so that
|
|
||||||
/// every system call get compiled in SFML (not inlined)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API SelectorBase
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SelectorBase();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Add a socket to watch
|
|
||||||
///
|
|
||||||
/// \param Socket : Socket to add
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Add(SocketHelper::SocketType Socket);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove a socket
|
|
||||||
///
|
|
||||||
/// \param Socket : Socket to remove
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Remove(SocketHelper::SocketType Socket);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove all sockets
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Wait and collect sockets which are ready for reading.
|
|
||||||
/// This functions will return either when at least one socket
|
|
||||||
/// is ready, or when the given time is out
|
|
||||||
///
|
|
||||||
/// \param Timeout : Timeout, in seconds (0 by default : no timeout)
|
|
||||||
///
|
|
||||||
/// \return Number of sockets ready to be read
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned int Wait(float Timeout = 0.f);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// After a call to Wait(), get the Index-th socket which is
|
|
||||||
/// ready for reading. The total number of sockets ready
|
|
||||||
/// is the integer returned by the previous call to Wait()
|
|
||||||
///
|
|
||||||
/// \param Index : Index of the socket to get
|
|
||||||
///
|
|
||||||
/// \return The Index-th socket
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketHelper::SocketType GetSocketReady(unsigned int Index);
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
fd_set mySet; ///< Set of socket to watch
|
|
||||||
fd_set mySetReady; ///< Set of socket which are ready for reading
|
|
||||||
int myMaxSocket; ///< Maximum socket index
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sf
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SELECTORBASE_HPP
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_SOCKET_HPP
|
||||||
|
#define SFML_SOCKET_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
#include <SFML/Network/SocketHandle.hpp>
|
||||||
|
#include <SFML/System/NonCopyable.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class SocketSelector;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Base class for all the socket types
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Socket : NonCopyable
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Status codes that may be returned by socket functions
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
Done, ///< The socket has sent / received the data
|
||||||
|
NotReady, ///< The socket is not ready to send / receive data yet
|
||||||
|
Disconnected, ///< The TCP socket has been disconnected
|
||||||
|
Error ///< An unexpected error happened
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Some special values used by sockets
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
AnyPort = 0 ///< Special value that tells the system to pick any available port
|
||||||
|
};
|
||||||
|
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~Socket();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the blocking state of the socket
|
||||||
|
///
|
||||||
|
/// In blocking mode, calls will not return until they have
|
||||||
|
/// completed their task. For example, a call to Receive in
|
||||||
|
/// blocking mode won't return until some data was actually
|
||||||
|
/// received.
|
||||||
|
/// In non-blocking mode, calls will always return immediately,
|
||||||
|
/// using the return code to signal whether there was data
|
||||||
|
/// available or not.
|
||||||
|
/// By default, all sockets are blocking.
|
||||||
|
///
|
||||||
|
/// \param blocking True to set the socket as blocking, false for non-blocking
|
||||||
|
///
|
||||||
|
/// \see isBlocking
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setBlocking(bool blocking);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the socket is in blocking or non-blocking mode
|
||||||
|
///
|
||||||
|
/// \return True if the socket is blocking, false otherwise
|
||||||
|
///
|
||||||
|
/// \see setBlocking
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool isBlocking() const;
|
||||||
|
|
||||||
|
protected :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Types of protocols that the socket can use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Tcp, ///< TCP protocol
|
||||||
|
Udp ///< UDP protocol
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
/// \param type Type of the socket (TCP or UDP)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket(Type type);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the internal handle of the socket
|
||||||
|
///
|
||||||
|
/// The returned handle may be invalid if the socket
|
||||||
|
/// was not created yet (or already destroyed).
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
/// \return The internal (OS-specific) handle of the socket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketHandle getHandle() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create the internal representation of the socket
|
||||||
|
///
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void create();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create the internal representation of the socket
|
||||||
|
/// from a socket handle
|
||||||
|
///
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
/// \param handle OS-specific handle of the socket to wrap
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void create(SocketHandle handle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Close the socket gracefully
|
||||||
|
///
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
friend class SocketSelector;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Type m_type; ///< Type of the socket (TCP or UDP)
|
||||||
|
SocketHandle m_socket; ///< Socket descriptor
|
||||||
|
bool m_isBlocking; ///< Current blocking mode of the socket
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_SOCKET_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Socket
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// This class mainly defines internal stuff to be used by
|
||||||
|
/// derived classes.
|
||||||
|
///
|
||||||
|
/// The only public features that it defines, and which
|
||||||
|
/// is therefore common to all the socket classes, is the
|
||||||
|
/// blocking state. All sockets can be set as blocking or
|
||||||
|
/// non-blocking.
|
||||||
|
///
|
||||||
|
/// In blocking mode, socket functions will hang until
|
||||||
|
/// the operation completes, which means that the entire
|
||||||
|
/// program (well, in fact the current thread if you use
|
||||||
|
/// multiple ones) will be stuck waiting for your socket
|
||||||
|
/// operation to complete.
|
||||||
|
///
|
||||||
|
/// In non-blocking mode, all the socket functions will
|
||||||
|
/// return immediately. If the socket is not ready to complete
|
||||||
|
/// the requested operation, the function simply returns
|
||||||
|
/// the proper status code (Socket::NotReady).
|
||||||
|
///
|
||||||
|
/// The default mode, which is blocking, is the one that is
|
||||||
|
/// generally used, in combination with threads or selectors.
|
||||||
|
/// The non-blocking mode is rather used in real-time
|
||||||
|
/// applications that run an endless loop that can poll
|
||||||
|
/// the socket often enough, and cannot afford blocking
|
||||||
|
/// this loop.
|
||||||
|
///
|
||||||
|
/// \see sf::TcpListener, sf::TcpSocket, sf::UdpSocket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -22,43 +22,36 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef SFML_SOCKETHELPER_HPP
|
#ifndef SFML_SOCKETHANDLE_HPP
|
||||||
#define SFML_SOCKETHELPER_HPP
|
#define SFML_SOCKETHANDLE_HPP
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Config.hpp>
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
#include <basetsd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
namespace Socket
|
////////////////////////////////////////////////////////////
|
||||||
{
|
// Define the low-level socket handle type, specific to
|
||||||
////////////////////////////////////////////////////////////
|
// each platform
|
||||||
/// Enumeration of status returned by socket functions
|
////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
enum Status
|
|
||||||
{
|
typedef UINT_PTR SocketHandle;
|
||||||
Done, ///< The socket has sent / received the data
|
|
||||||
NotReady, ///< The socket is not ready to send / receive data yet
|
#else
|
||||||
Disconnected, ///< The TCP socket has been disconnected
|
|
||||||
Error ///< An unexpected error happened
|
typedef int SocketHandle;
|
||||||
};
|
|
||||||
}
|
#endif
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
#ifdef SFML_SYSTEM_WINDOWS
|
#endif // SFML_SOCKETHANDLE_HPP
|
||||||
|
|
||||||
#include <SFML/Network/Win32/SocketHelper.hpp>
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <SFML/Network/Unix/SocketHelper.hpp>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SOCKETHELPER_HPP
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_SOCKETSELECTOR_HPP
|
||||||
|
#define SFML_SOCKETSELECTOR_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Socket;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Multiplexer that allows to read from multiple sockets
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API SocketSelector
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy Instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector(const SocketSelector& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~SocketSelector();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Add a new socket to the selector
|
||||||
|
///
|
||||||
|
/// This function keeps a weak reference to the socket,
|
||||||
|
/// so you have to make sure that the socket is not destroyed
|
||||||
|
/// while it is stored in the selector.
|
||||||
|
/// This function does nothing if the socket is not valid.
|
||||||
|
///
|
||||||
|
/// \param socket Reference to the socket to add
|
||||||
|
///
|
||||||
|
/// \see remove, clear
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void add(Socket& socket);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove a socket from the selector
|
||||||
|
///
|
||||||
|
/// This function doesn't destroy the socket, it simply
|
||||||
|
/// removes the reference that the selector has to it.
|
||||||
|
///
|
||||||
|
/// \param socket Reference to the socket to remove
|
||||||
|
///
|
||||||
|
/// \see add, clear
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void remove(Socket& socket);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove all the sockets stored in the selector
|
||||||
|
///
|
||||||
|
/// This function doesn't destroy any instance, it simply
|
||||||
|
/// removes all the references that the selector has to
|
||||||
|
/// external sockets.
|
||||||
|
///
|
||||||
|
/// \see add, remove
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Wait until one or more sockets are ready to receive
|
||||||
|
///
|
||||||
|
/// This function returns as soon as at least one socket has
|
||||||
|
/// some data available to be received. To know which sockets are
|
||||||
|
/// ready, use the isReady function.
|
||||||
|
/// If you use a timeout and no socket is ready before the timeout
|
||||||
|
/// is over, the function returns false.
|
||||||
|
///
|
||||||
|
/// \param timeout Maximum time to wait, (use Time::Zero for infinity)
|
||||||
|
///
|
||||||
|
/// \return True if there are sockets ready, false otherwise
|
||||||
|
///
|
||||||
|
/// \see isReady
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool wait(Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Test a socket to know if it is ready to receive data
|
||||||
|
///
|
||||||
|
/// This function must be used after a call to Wait, to know
|
||||||
|
/// which sockets are ready to receive data. If a socket is
|
||||||
|
/// ready, a call to receive will never block because we know
|
||||||
|
/// that there is data available to read.
|
||||||
|
/// Note that if this function returns true for a TcpListener,
|
||||||
|
/// this means that it is ready to accept a new connection.
|
||||||
|
///
|
||||||
|
/// \param socket Socket to test
|
||||||
|
///
|
||||||
|
/// \return True if the socket is ready to read, false otherwise
|
||||||
|
///
|
||||||
|
/// \see isReady
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool isReady(Socket& socket) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector& operator =(const SocketSelector& right);
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
struct SocketSelectorImpl;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelectorImpl* m_impl; ///< Opaque pointer to the implementation (which requires OS-specific types)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_SOCKETSELECTOR_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SocketSelector
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// Socket selectors provide a way to wait until some data is
|
||||||
|
/// available on a set of sockets, instead of just one. This
|
||||||
|
/// is convenient when you have multiple sockets that may
|
||||||
|
/// possibly receive data, but you don't know which one will
|
||||||
|
/// be ready first. In particular, it avoids to use a thread
|
||||||
|
/// for each socket; with selectors, a single thread can handle
|
||||||
|
/// all the sockets.
|
||||||
|
///
|
||||||
|
/// All types of sockets can be used in a selector:
|
||||||
|
/// \li sf::TcpListener
|
||||||
|
/// \li sf::TcpSocket
|
||||||
|
/// \li sf::UdpSocket
|
||||||
|
///
|
||||||
|
/// A selector doesn't store its own copies of the sockets
|
||||||
|
/// (socket classes are not copyable anyway), it simply keeps
|
||||||
|
/// a reference to the original sockets that you pass to the
|
||||||
|
/// "add" function. Therefore, you can't use the selector as a
|
||||||
|
/// socket container, you must store them oustide and make sure
|
||||||
|
/// that they are alive as long as they are used in the selector.
|
||||||
|
///
|
||||||
|
/// Using a selector is simple:
|
||||||
|
/// \li populate the selector with all the sockets that you want to observe
|
||||||
|
/// \li make it wait until there is data available on any of the sockets
|
||||||
|
/// \li test each socket to find out which ones are ready
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a socket to listen to new connections
|
||||||
|
/// sf::TcpListener listener;
|
||||||
|
/// listener.listen(55001);
|
||||||
|
///
|
||||||
|
/// // Create a list to store the future clients
|
||||||
|
/// std::list<sf::TcpSocket*> clients;
|
||||||
|
///
|
||||||
|
/// // Create a selector
|
||||||
|
/// sf::SocketSelector selector;
|
||||||
|
///
|
||||||
|
/// // Add the listener to the selector
|
||||||
|
/// selector.add(listener);
|
||||||
|
///
|
||||||
|
/// // Endless loop that waits for new connections
|
||||||
|
/// while (running)
|
||||||
|
/// {
|
||||||
|
/// // Make the selector wait for data on any socket
|
||||||
|
/// if (selector.wait())
|
||||||
|
/// {
|
||||||
|
/// // Test the listener
|
||||||
|
/// if (selector.isReady(listener))
|
||||||
|
/// {
|
||||||
|
/// // The listener is ready: there is a pending connection
|
||||||
|
/// sf::TcpSocket* client = new sf::TcpSocket;
|
||||||
|
/// if (listener.accept(*client) == sf::Socket::Done)
|
||||||
|
/// {
|
||||||
|
/// // Add the new client to the clients list
|
||||||
|
/// clients.push_back(client);
|
||||||
|
///
|
||||||
|
/// // Add the new client to the selector so that we will
|
||||||
|
/// // be notified when he sends something
|
||||||
|
/// selector.add(*client);
|
||||||
|
/// }
|
||||||
|
/// else
|
||||||
|
/// {
|
||||||
|
/// // Error, we won't get a new connection, delete the socket
|
||||||
|
/// delete client;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// else
|
||||||
|
/// {
|
||||||
|
/// // The listener socket is not ready, test all other sockets (the clients)
|
||||||
|
/// for (std::list<sf::TcpSocket*>::iterator it = clients.begin(); it != clients.end(); ++it)
|
||||||
|
/// {
|
||||||
|
/// sf::TcpSocket& client = **it;
|
||||||
|
/// if (selector.isReady(client))
|
||||||
|
/// {
|
||||||
|
/// // The client has sent some data, we can receive it
|
||||||
|
/// sf::Packet packet;
|
||||||
|
/// if (client.receive(packet) == sf::Socket::Done)
|
||||||
|
/// {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see sf::Socket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -1,227 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef SFML_SOCKETTCP_HPP
|
|
||||||
#define SFML_SOCKETTCP_HPP
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
class Packet;
|
|
||||||
class IPAddress;
|
|
||||||
template <typename> class Selector;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// SocketTCP wraps a socket using TCP protocol to
|
|
||||||
/// send data safely (but a bit slower)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API SocketTCP
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketTCP();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Change the blocking state of the socket.
|
|
||||||
/// The default behaviour of a socket is blocking
|
|
||||||
///
|
|
||||||
/// \param Blocking : Pass true to set the socket as blocking, or false for non-blocking
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SetBlocking(bool Blocking);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Connect to another computer on a specified port
|
|
||||||
///
|
|
||||||
/// \param Port : Port to use for transfers (warning : ports < 1024 are reserved)
|
|
||||||
/// \param HostAddress : IP Address of the host to connect to
|
|
||||||
/// \param Timeout : Maximum time to wait, in seconds (0 by default : no timeout) (this parameter is ignored for non-blocking sockets)
|
|
||||||
///
|
|
||||||
/// \return True if operation has been successful
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout = 0.f);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Listen to a specified port for incoming data or connections
|
|
||||||
///
|
|
||||||
/// \param Port : Port to listen to
|
|
||||||
///
|
|
||||||
/// \return True if operation has been successful
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Listen(unsigned short Port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Wait for a connection (must be listening to a port).
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
///
|
|
||||||
/// \param Connected : Socket containing the connection with the connected client
|
|
||||||
/// \param Address : Pointer to an address to fill with client infos (NULL by default)
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Accept(SocketTCP& Connected, IPAddress* Address = NULL);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send an array of bytes to the host (must be connected first)
|
|
||||||
///
|
|
||||||
/// \param Data : Pointer to the bytes to send
|
|
||||||
/// \param Size : Number of bytes to send
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Send(const char* Data, std::size_t Size);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive an array of bytes from the host (must be connected first).
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
///
|
|
||||||
/// \param Data : Pointer to a byte array to fill (make sure it is big enough)
|
|
||||||
/// \param MaxSize : Maximum number of bytes to read
|
|
||||||
/// \param SizeReceived : Number of bytes received
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a packet of data to the host (must be connected first)
|
|
||||||
///
|
|
||||||
/// \param PacketToSend : Packet to send
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Send(Packet& PacketToSend);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive a packet from the host (must be connected first).
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
///
|
|
||||||
/// \param PacketToReceive : Packet to fill with received data
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Receive(Packet& PacketToReceive);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Close the socket
|
|
||||||
///
|
|
||||||
/// \return True if operation has been successful
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Close();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Check if the socket is in a valid state ; this function
|
|
||||||
/// can be called any time to check if the socket is OK
|
|
||||||
///
|
|
||||||
/// \return True if the socket is valid
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IsValid() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator ==
|
|
||||||
///
|
|
||||||
/// \param Other : Socket to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this == Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator ==(const SocketTCP& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator !=
|
|
||||||
///
|
|
||||||
/// \param Other : Socket to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this != Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator !=(const SocketTCP& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator <.
|
|
||||||
/// Provided for compatibility with standard containers, as
|
|
||||||
/// comparing two sockets doesn't make much sense...
|
|
||||||
///
|
|
||||||
/// \param Other : Socket to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this < Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator <(const SocketTCP& Other) const;
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
friend class Selector<SocketTCP>;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Construct the socket from a socket descriptor
|
|
||||||
/// (for internal use only)
|
|
||||||
///
|
|
||||||
/// \param Descriptor : Socket descriptor
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketTCP(SocketHelper::SocketType Descriptor);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Create the socket
|
|
||||||
///
|
|
||||||
/// \param Descriptor : System socket descriptor to use (0 by default -- create a new socket)
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Create(SocketHelper::SocketType Descriptor = 0);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketHelper::SocketType mySocket; ///< Socket descriptor
|
|
||||||
Uint32 myPendingHeader; ///< Data of the current pending packet header, if any
|
|
||||||
Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any
|
|
||||||
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any
|
|
||||||
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any
|
|
||||||
bool myIsBlocking; ///< Is the socket blocking or non-blocking ?
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sf
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SOCKETTCP_HPP
|
|
|
@ -1,228 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef SFML_SOCKETUDP_HPP
|
|
||||||
#define SFML_SOCKETUDP_HPP
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
class Packet;
|
|
||||||
class IPAddress;
|
|
||||||
template <typename> class Selector;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// SocketUDP wraps a socket using UDP protocol to
|
|
||||||
/// send data fastly (but with less safety)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class SFML_API SocketUDP
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketUDP();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Change the blocking state of the socket.
|
|
||||||
/// The default behaviour of a socket is blocking
|
|
||||||
///
|
|
||||||
/// \param Blocking : Pass true to set the socket as blocking, or false for non-blocking
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SetBlocking(bool Blocking);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Bind the socket to a specific port
|
|
||||||
///
|
|
||||||
/// \param Port : Port to bind the socket to
|
|
||||||
///
|
|
||||||
/// \return True if operation has been successful
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Bind(unsigned short Port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Unbind the socket from its previous port, if any
|
|
||||||
///
|
|
||||||
/// \return True if operation has been successful
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Unbind();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send an array of bytes
|
|
||||||
///
|
|
||||||
/// \param Data : Pointer to the bytes to send
|
|
||||||
/// \param Size : Number of bytes to send
|
|
||||||
/// \param Address : Address of the computer to send the packet to
|
|
||||||
/// \param Port : Port to send the data to
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive an array of bytes.
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
///
|
|
||||||
/// \param Data : Pointer to a byte array to fill (make sure it is big enough)
|
|
||||||
/// \param MaxSize : Maximum number of bytes to read
|
|
||||||
/// \param SizeReceived : Number of bytes received
|
|
||||||
/// \param Address : Address of the computer which sent the data
|
|
||||||
/// \param Port : Port on which the remote computer sent the data
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address, unsigned short& Port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a packet of data
|
|
||||||
///
|
|
||||||
/// \param PacketToSend : Packet to send
|
|
||||||
/// \param Address : Address of the computer to send the packet to
|
|
||||||
/// \param Port : Port to send the data to
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive a packet.
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
///
|
|
||||||
/// \param PacketToReceive : Packet to fill with received data
|
|
||||||
/// \param Address : Address of the computer which sent the packet
|
|
||||||
/// \param Port : Port on which the remote computer sent the data
|
|
||||||
///
|
|
||||||
/// \return Status code
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Close the socket
|
|
||||||
///
|
|
||||||
/// \return True if operation has been successful
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Close();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Check if the socket is in a valid state ; this function
|
|
||||||
/// can be called any time to check if the socket is OK
|
|
||||||
///
|
|
||||||
/// \return True if the socket is valid
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IsValid() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the port the socket is currently bound to
|
|
||||||
///
|
|
||||||
/// \return Current port (0 means the socket is not bound)
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned short GetPort() const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator ==
|
|
||||||
///
|
|
||||||
/// \param Other : Socket to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this == Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator ==(const SocketUDP& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator !=
|
|
||||||
///
|
|
||||||
/// \param Other : Socket to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this != Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator !=(const SocketUDP& Other) const;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator <.
|
|
||||||
/// Provided for compatibility with standard containers, as
|
|
||||||
/// comparing two sockets doesn't make much sense...
|
|
||||||
///
|
|
||||||
/// \param Other : Socket to compare
|
|
||||||
///
|
|
||||||
/// \return True if *this < Other
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool operator <(const SocketUDP& Other) const;
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
friend class Selector<SocketUDP>;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Construct the socket from a socket descriptor
|
|
||||||
/// (for internal use only)
|
|
||||||
///
|
|
||||||
/// \param Descriptor : Socket descriptor
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketUDP(SocketHelper::SocketType Descriptor);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Create the socket
|
|
||||||
///
|
|
||||||
/// \param Descriptor : System socket descriptor to use (0 by default -- create a new socket)
|
|
||||||
///
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Create(SocketHelper::SocketType Descriptor = 0);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketHelper::SocketType mySocket; ///< Socket identifier
|
|
||||||
unsigned short myPort; ///< Port to which the socket is bound
|
|
||||||
Uint32 myPendingHeader; ///< Data of the current pending packet header, if any
|
|
||||||
Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any
|
|
||||||
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any
|
|
||||||
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any
|
|
||||||
bool myIsBlocking; ///< Is the socket blocking or non-blocking ?
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace sf
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SOCKETUDP_HPP
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_TCPLISTENER_HPP
|
||||||
|
#define SFML_TCPLISTENER_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class TcpSocket;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Socket that listens to new TCP connections
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API TcpListener : public Socket
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpListener();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port to which the socket is bound locally
|
||||||
|
///
|
||||||
|
/// If the socket is not listening to a port, this function
|
||||||
|
/// returns 0.
|
||||||
|
///
|
||||||
|
/// \return Port to which the socket is bound
|
||||||
|
///
|
||||||
|
/// \see listen
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short getLocalPort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start listening for connections
|
||||||
|
///
|
||||||
|
/// This functions makes the socket listen to the specified
|
||||||
|
/// port, waiting for new connections.
|
||||||
|
/// If the socket was previously listening to another port,
|
||||||
|
/// it will be stopped first and bound to the new port.
|
||||||
|
///
|
||||||
|
/// \param port Port to listen for new connections
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see accept, close
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status listen(unsigned short port);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop listening and close the socket
|
||||||
|
///
|
||||||
|
/// This function gracefully stops the listener. If the
|
||||||
|
/// socket is not listening, this function has no effect.
|
||||||
|
///
|
||||||
|
/// \see listen
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void close();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Accept a new connection
|
||||||
|
///
|
||||||
|
/// If the socket is in blocking mode, this function will
|
||||||
|
/// not return until a connection is actually received.
|
||||||
|
///
|
||||||
|
/// \param socket Socket that will hold the new connection
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see listen
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status accept(TcpSocket& socket);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_TCPLISTENER_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::TcpListener
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// A listener socket is a special type of socket that listens to
|
||||||
|
/// a given port and waits for connections on that port.
|
||||||
|
/// This is all it can do.
|
||||||
|
///
|
||||||
|
/// When a new connection is received, you must call accept and
|
||||||
|
/// the listener returns a new instance of sf::TcpSocket that
|
||||||
|
/// is properly initialized and can be used to communicate with
|
||||||
|
/// the new client.
|
||||||
|
///
|
||||||
|
/// Listener sockets are specific to the TCP protocol,
|
||||||
|
/// UDP sockets are connectionless and can therefore communicate
|
||||||
|
/// directly. As a consequence, a listener socket will always
|
||||||
|
/// return the new connections as sf::TcpSocket instances.
|
||||||
|
///
|
||||||
|
/// A listener is automatically closed on destruction, like all
|
||||||
|
/// other types of socket. However if you want to stop listening
|
||||||
|
/// before the socket is destroyed, you can call its close()
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a listener socket and make it wait for new
|
||||||
|
/// // connections on port 55001
|
||||||
|
/// sf::TcpListener listener;
|
||||||
|
/// listener.listen(55001);
|
||||||
|
///
|
||||||
|
/// // Endless loop that waits for new connections
|
||||||
|
/// while (running)
|
||||||
|
/// {
|
||||||
|
/// sf::TcpSocket client;
|
||||||
|
/// if (listener.accept(client) == sf::Socket::Done)
|
||||||
|
/// {
|
||||||
|
/// // A new client just connected!
|
||||||
|
/// std::cout << "New connection received from " << client.getRemoteAddress() << std::endl;
|
||||||
|
/// doSomethingWith(client);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see sf::TcpSocket, sf::Socket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,292 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_TCPSOCKET_HPP
|
||||||
|
#define SFML_TCPSOCKET_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class TcpListener;
|
||||||
|
class IpAddress;
|
||||||
|
class Packet;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized socket using the TCP protocol
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API TcpSocket : public Socket
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpSocket();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port to which the socket is bound locally
|
||||||
|
///
|
||||||
|
/// If the socket is not connected, this function returns 0.
|
||||||
|
///
|
||||||
|
/// \return Port to which the socket is bound
|
||||||
|
///
|
||||||
|
/// \see connect, getRemotePort
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short getLocalPort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the address of the connected peer
|
||||||
|
///
|
||||||
|
/// It the socket is not connected, this function returns
|
||||||
|
/// sf::IpAddress::None.
|
||||||
|
///
|
||||||
|
/// \return Address of the remote peer
|
||||||
|
///
|
||||||
|
/// \see getRemotePort
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
IpAddress getRemoteAddress() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port of the connected peer to which
|
||||||
|
/// the socket is connected
|
||||||
|
///
|
||||||
|
/// If the socket is not connected, this function returns 0.
|
||||||
|
///
|
||||||
|
/// \return Remote port to which the socket is connected
|
||||||
|
///
|
||||||
|
/// \see getRemoteAddress
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short getRemotePort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Connect the socket to a remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function may take a while, especially
|
||||||
|
/// if the remote peer is not reachable. The last parameter allows
|
||||||
|
/// you to stop trying to connect after a given timeout.
|
||||||
|
/// If the socket was previously connected, it is first disconnected.
|
||||||
|
///
|
||||||
|
/// \param remoteAddress Address of the remote peer
|
||||||
|
/// \param remotePort Port of the remote peer
|
||||||
|
/// \param timeout Optional maximum time to wait
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see disconnect
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status connect(const IpAddress& remoteAddress, unsigned short remotePort, Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disconnect the socket from its remote peer
|
||||||
|
///
|
||||||
|
/// This function gracefully closes the connection. If the
|
||||||
|
/// socket is not connected, this function has no effect.
|
||||||
|
///
|
||||||
|
/// \see connect
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send raw data to the remote peer
|
||||||
|
///
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
|
/// \param size Number of bytes to send
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see receive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status send(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive raw data from the remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until some
|
||||||
|
/// bytes are actually received.
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the array to fill with the received bytes
|
||||||
|
/// \param size Maximum number of bytes that can be received
|
||||||
|
/// \param received This variable is filled with the actual number of bytes received
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see send
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status receive(void* data, std::size_t size, std::size_t& received);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a formatted packet of data to the remote peer
|
||||||
|
///
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to send
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see receive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status send(Packet& packet);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive a formatted packet of data from the remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until the whole packet
|
||||||
|
/// has been received.
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to fill with the received data
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see send
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status receive(Packet& packet);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
friend class TcpListener;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure holding the data of a pending packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct PendingPacket
|
||||||
|
{
|
||||||
|
PendingPacket();
|
||||||
|
|
||||||
|
Uint32 Size; ///< Data of packet size
|
||||||
|
std::size_t SizeReceived; ///< Number of size bytes received so far
|
||||||
|
std::vector<char> Data; ///< Data of the packet
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
PendingPacket m_pendingPacket; ///< Temporary data of the packet currently being received
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_TCPSOCKET_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::TcpSocket
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// TCP is a connected protocol, which means that a TCP
|
||||||
|
/// socket can only communicate with the host it is connected
|
||||||
|
/// to. It can't send or receive anything if it is not connected.
|
||||||
|
///
|
||||||
|
/// The TCP protocol is reliable but adds a slight overhead.
|
||||||
|
/// It ensures that your data will always be received in order
|
||||||
|
/// and without errors (no data corrupted, lost or duplicated).
|
||||||
|
///
|
||||||
|
/// When a socket is connected to a remote host, you can
|
||||||
|
/// retrieve informations about this host with the
|
||||||
|
/// getRemoteAddress and getRemotePort functions. You can
|
||||||
|
/// also get the local port to which the socket is bound
|
||||||
|
/// (which is automatically chosen when the socket is connected),
|
||||||
|
/// with the getLocalPort function.
|
||||||
|
///
|
||||||
|
/// Sending and receiving data can use either the low-level
|
||||||
|
/// or the high-level functions. The low-level functions
|
||||||
|
/// process a raw sequence of bytes, and cannot ensure that
|
||||||
|
/// one call to Send will exactly match one call to Receive
|
||||||
|
/// at the other end of the socket.
|
||||||
|
///
|
||||||
|
/// The high-level interface uses packets (see sf::Packet),
|
||||||
|
/// which are easier to use and provide more safety regarding
|
||||||
|
/// the data that is exchanged. You can look at the sf::Packet
|
||||||
|
/// class to get more details about how they work.
|
||||||
|
///
|
||||||
|
/// The socket is automatically disconnected when it is destroyed,
|
||||||
|
/// but if you want to explicitely close the connection while
|
||||||
|
/// the socket instance is still alive, you can call disconnect.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // ----- The client -----
|
||||||
|
///
|
||||||
|
/// // Create a socket and connect it to 192.168.1.50 on port 55001
|
||||||
|
/// sf::TcpSocket socket;
|
||||||
|
/// socket.connect("192.168.1.50", 55001);
|
||||||
|
///
|
||||||
|
/// // Send a message to the connected host
|
||||||
|
/// std::string message = "Hi, I am a client";
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1);
|
||||||
|
///
|
||||||
|
/// // Receive an answer from the server
|
||||||
|
/// char buffer[1024];
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// socket.receive(buffer, sizeof(buffer), received);
|
||||||
|
/// std::cout << "The server said: " << buffer << std::endl;
|
||||||
|
///
|
||||||
|
/// // ----- The server -----
|
||||||
|
///
|
||||||
|
/// // Create a listener to wait for incoming connections on port 55001
|
||||||
|
/// sf::TcpListener listener;
|
||||||
|
/// listener.listen(55001);
|
||||||
|
///
|
||||||
|
/// // Wait for a connection
|
||||||
|
/// sf::TcpSocket socket;
|
||||||
|
/// listener.accept(socket);
|
||||||
|
/// std::cout << "New client connected: " << socket.getRemoteAddress() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Receive a message from the client
|
||||||
|
/// char buffer[1024];
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// socket.receive(buffer, sizeof(buffer), received);
|
||||||
|
/// std::cout << "The client said: " << buffer << std::endl;
|
||||||
|
///
|
||||||
|
/// // Send an answer
|
||||||
|
/// std::string message = "Welcome, client";
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see sf::Socket, sf::UdpSocket, sf::Packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,283 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_UDPSOCKET_HPP
|
||||||
|
#define SFML_UDPSOCKET_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class IpAddress;
|
||||||
|
class Packet;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized socket using the UDP protocol
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API UdpSocket : public Socket
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Constants
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MaxDatagramSize = 65507 ///< The maximum number of bytes that can be sent in a single UDP datagram
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
UdpSocket();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port to which the socket is bound locally
|
||||||
|
///
|
||||||
|
/// If the socket is not bound to a port, this function
|
||||||
|
/// returns 0.
|
||||||
|
///
|
||||||
|
/// \return Port to which the socket is bound
|
||||||
|
///
|
||||||
|
/// \see bind
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short getLocalPort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Bind the socket to a specific port
|
||||||
|
///
|
||||||
|
/// Binding the socket to a port is necessary for being
|
||||||
|
/// able to receive data on that port.
|
||||||
|
/// You can use the special value Socket::AnyPort to tell the
|
||||||
|
/// system to automatically pick an available port, and then
|
||||||
|
/// call getLocalPort to retrieve the chosen port.
|
||||||
|
///
|
||||||
|
/// \param port Port to bind the socket to
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see unbind, getLocalPort
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status bind(unsigned short port);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Unbind the socket from the local port to which it is bound
|
||||||
|
///
|
||||||
|
/// The port that the socket was previously using is immediately
|
||||||
|
/// available after this function is called. If the
|
||||||
|
/// socket is not bound to a port, this function has no effect.
|
||||||
|
///
|
||||||
|
/// \see bind
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void unbind();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send raw data to a remote peer
|
||||||
|
///
|
||||||
|
/// Make sure that \a size is not greater than
|
||||||
|
/// UdpSocket::MaxDatagramSize, otherwise this function will
|
||||||
|
/// fail and no data will be sent.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
|
/// \param size Number of bytes to send
|
||||||
|
/// \param remoteAddress Address of the receiver
|
||||||
|
/// \param remotePort Port of the receiver to send the data to
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see receive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status send(const void* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive raw data from a remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until some
|
||||||
|
/// bytes are actually received.
|
||||||
|
/// Be careful to use a buffer which is large enough for
|
||||||
|
/// the data that you intend to receive, if it is too small
|
||||||
|
/// then an error will be returned and *all* the data will
|
||||||
|
/// be lost.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the array to fill with the received bytes
|
||||||
|
/// \param size Maximum number of bytes that can be received
|
||||||
|
/// \param received This variable is filled with the actual number of bytes received
|
||||||
|
/// \param remoteAddress Address of the peer that sent the data
|
||||||
|
/// \param remotePort Port of the peer that sent the data
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see send
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status receive(void* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a formatted packet of data to a remote peer
|
||||||
|
///
|
||||||
|
/// Make sure that the packet size is not greater than
|
||||||
|
/// UdpSocket::MaxDatagramSize, otherwise this function will
|
||||||
|
/// fail and no data will be sent.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to send
|
||||||
|
/// \param remoteAddress Address of the receiver
|
||||||
|
/// \param remotePort Port of the receiver to send the data to
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see receive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive a formatted packet of data from a remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until the whole packet
|
||||||
|
/// has been received.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to fill with the received data
|
||||||
|
/// \param remoteAddress Address of the peer that sent the data
|
||||||
|
/// \param remotePort Port of the peer that sent the data
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see send
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<char> m_buffer; ///< Temporary buffer holding the received data in Receive(Packet)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_UDPSOCKET_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::UdpSocket
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// A UDP socket is a connectionless socket. Instead of
|
||||||
|
/// connecting once to a remote host, like TCP sockets,
|
||||||
|
/// it can send to and receive from any host at any time.
|
||||||
|
///
|
||||||
|
/// It is a datagram protocol: bounded blocks of data (datagrams)
|
||||||
|
/// are transfered over the network rather than a continuous
|
||||||
|
/// stream of data (TCP). Therefore, one call to send will always
|
||||||
|
/// match one call to receive (if the datagram is not lost),
|
||||||
|
/// with the same data that was sent.
|
||||||
|
///
|
||||||
|
/// The UDP protocol is lightweight but unreliable. Unreliable
|
||||||
|
/// means that datagrams may be duplicated, be lost or
|
||||||
|
/// arrive reordered. However, if a datagram arrives, its
|
||||||
|
/// data is guaranteed to be valid.
|
||||||
|
///
|
||||||
|
/// UDP is generally used for real-time communication
|
||||||
|
/// (audio or video streaming, real-time games, etc.) where
|
||||||
|
/// speed is crucial and lost data doesn't matter much.
|
||||||
|
///
|
||||||
|
/// Sending and receiving data can use either the low-level
|
||||||
|
/// or the high-level functions. The low-level functions
|
||||||
|
/// process a raw sequence of bytes, whereas the high-level
|
||||||
|
/// interface uses packets (see sf::Packet), which are easier
|
||||||
|
/// to use and provide more safety regarding the data that is
|
||||||
|
/// exchanged. You can look at the sf::Packet class to get
|
||||||
|
/// more details about how they work.
|
||||||
|
///
|
||||||
|
/// It is important to note that UdpSocket is unable to send
|
||||||
|
/// datagrams bigger than MaxDatagramSize. In this case, it
|
||||||
|
/// returns an error and doesn't send anything. This applies
|
||||||
|
/// to both raw data and packets. Indeed, even packets are
|
||||||
|
/// unable to split and recompose data, due to the unreliability
|
||||||
|
/// of the protocol (dropped, mixed or duplicated datagrams may
|
||||||
|
/// lead to a big mess when trying to recompose a packet).
|
||||||
|
///
|
||||||
|
/// If the socket is bound to a port, it is automatically
|
||||||
|
/// unbound from it when the socket is destroyed. However,
|
||||||
|
/// you can unbind the socket explicitely with the Unbind
|
||||||
|
/// function if necessary, to stop receiving messages or
|
||||||
|
/// make the port available for other sockets.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // ----- The client -----
|
||||||
|
///
|
||||||
|
/// // Create a socket and bind it to the port 55001
|
||||||
|
/// sf::UdpSocket socket;
|
||||||
|
/// socket.bind(55001);
|
||||||
|
///
|
||||||
|
/// // Send a message to 192.168.1.50 on port 55002
|
||||||
|
/// std::string message = "Hi, I am " + sf::IpAddress::getLocalAddress().toString();
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1, "192.168.1.50", 55002);
|
||||||
|
///
|
||||||
|
/// // Receive an answer (most likely from 192.168.1.50, but could be anyone else)
|
||||||
|
/// char buffer[1024];
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// sf::IpAddress sender;
|
||||||
|
/// unsigned short port;
|
||||||
|
/// socket.receive(buffer, sizeof(buffer), received, sender, port);
|
||||||
|
/// std::cout << sender.ToString() << " said: " << buffer << std::endl;
|
||||||
|
///
|
||||||
|
/// // ----- The server -----
|
||||||
|
///
|
||||||
|
/// // Create a socket and bind it to the port 55002
|
||||||
|
/// sf::UdpSocket socket;
|
||||||
|
/// socket.bind(55002);
|
||||||
|
///
|
||||||
|
/// // Receive a message from anyone
|
||||||
|
/// char buffer[1024];
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// sf::IpAddress sender;
|
||||||
|
/// unsigned short port;
|
||||||
|
/// socket.receive(buffer, sizeof(buffer), received, sender, port);
|
||||||
|
/// std::cout << sender.ToString() << " said: " << buffer << std::endl;
|
||||||
|
///
|
||||||
|
/// // Send an answer
|
||||||
|
/// std::string message = "Welcome " + sender.toString();
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1, sender, port);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see sf::Socket, sf::TcpSocket, sf::Packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -30,14 +30,27 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <SFML/Config.hpp>
|
#include <SFML/Config.hpp>
|
||||||
// #include <SFML/System/Clock.hpp>
|
//#include <SFML/System/Clock.hpp>
|
||||||
// #include <SFML/System/Lock.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
// #include <SFML/System/Mutex.hpp>
|
//#include <SFML/System/InputStream.hpp>
|
||||||
// #include <SFML/System/Randomizer.hpp>
|
//#include <SFML/System/Lock.hpp>
|
||||||
// #include <SFML/System/Sleep.hpp>
|
//#include <SFML/System/Mutex.hpp>
|
||||||
// #include <SFML/System/Thread.hpp>
|
//#include <SFML/System/Sleep.hpp>
|
||||||
// #include <SFML/System/Unicode.hpp>
|
#include <SFML/System/String.hpp>
|
||||||
// #include <SFML/System/Vector2.hpp>
|
//#include <SFML/System/Thread.hpp>
|
||||||
// #include <SFML/System/Vector3.hpp>
|
//#include <SFML/System/ThreadLocal.hpp>
|
||||||
|
//#include <SFML/System/ThreadLocalPtr.hpp>
|
||||||
|
#include <SFML/System/Utf.hpp>
|
||||||
|
//#include <SFML/System/Vector2.hpp>
|
||||||
|
//#include <SFML/System/Vector3.hpp>
|
||||||
|
|
||||||
#endif // SFML_SYSTEM_HPP
|
#endif // SFML_SYSTEM_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \defgroup system System module
|
||||||
|
///
|
||||||
|
/// Base module of SFML, defining various utilities. It provides
|
||||||
|
/// vector classes, unicode strings and conversion functions,
|
||||||
|
/// threads and mutexes, timing classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_ERR_HPP
|
||||||
|
#define SFML_ERR_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Standard stream used by SFML to output warnings and errors
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API std::ostream& err();
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_ERR_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \fn sf::err
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// By default, sf::err() outputs to the same location as std::cerr,
|
||||||
|
/// (-> the stderr descriptor) which is the console if there's
|
||||||
|
/// one available.
|
||||||
|
///
|
||||||
|
/// It is a standard std::ostream instance, so it supports all the
|
||||||
|
/// insertion operations defined by the STL
|
||||||
|
/// (operator <<, manipulators, etc.).
|
||||||
|
///
|
||||||
|
/// sf::err() can be redirected to write to another output, independantly
|
||||||
|
/// of std::cerr, by using the rdbuf() function provided by the
|
||||||
|
/// std::ostream class.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// // Redirect to a file
|
||||||
|
/// std::ofstream file("sfml-log.txt");
|
||||||
|
/// std::streambuf* previous = sf::err().rdbuf(file.rdbuf());
|
||||||
|
///
|
||||||
|
/// // Redirect to nothing
|
||||||
|
/// sf::err().rdbuf(NULL);
|
||||||
|
///
|
||||||
|
/// // Restore the original output
|
||||||
|
/// sf::err().rdbuf(previous);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,48 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_SYSTEM_EXPORT_HPP
|
||||||
|
#define SFML_SYSTEM_EXPORT_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Define portable import / export macros
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_SYSTEM_EXPORTS)
|
||||||
|
|
||||||
|
#define SFML_SYSTEM_API SFML_API_EXPORT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_SYSTEM_API SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_SYSTEM_EXPORT_HPP
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -28,21 +28,26 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Config.hpp>
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Utility base class to easily declare non-copyable classes.
|
/// \brief Utility class that makes any derived
|
||||||
/// Just inherit from NonCopyable to get a non-copyable class
|
/// class non-copyable
|
||||||
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
struct SFML_API NonCopyable
|
class SFML_SYSTEM_API NonCopyable
|
||||||
{
|
{
|
||||||
protected :
|
protected :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// The default constructor won't be generated, so provide it
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Because this class has a copy constructor, the compiler
|
||||||
|
/// will not automatically generate the default constructor.
|
||||||
|
/// That's why we must define it explicitely.
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
NonCopyable() {}
|
NonCopyable() {}
|
||||||
|
@ -50,15 +55,25 @@ protected :
|
||||||
private :
|
private :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Copy constructor : declare it private and don't implement
|
/// \brief Disabled copy constructor
|
||||||
/// it to prevent from calling it
|
///
|
||||||
|
/// By making the copy constructor private, the compiler will
|
||||||
|
/// trigger an error if anyone outside tries to use it.
|
||||||
|
/// To prevent NonCopyable or friend classes from using it,
|
||||||
|
/// we also give no definition, so that the linker will
|
||||||
|
/// produce an error if the first protection was inefficient.
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
NonCopyable(const NonCopyable&);
|
NonCopyable(const NonCopyable&);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Assignment operator : declare it private and don't implement
|
/// \brief Disabled assignment operator
|
||||||
/// it to prevent from calling it
|
///
|
||||||
|
/// By making the assignment operator private, the compiler will
|
||||||
|
/// trigger an error if anyone outside tries to use it.
|
||||||
|
/// To prevent NonCopyable or friend classes from using it,
|
||||||
|
/// we also give no definition, so that the linker will
|
||||||
|
/// produce an error if the first protection was inefficient.
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
NonCopyable& operator =(const NonCopyable&);
|
NonCopyable& operator =(const NonCopyable&);
|
||||||
|
@ -68,3 +83,37 @@ private :
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_NONCOPYABLE_HPP
|
#endif // SFML_NONCOPYABLE_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::NonCopyable
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// This class makes its instances non-copyable, by explicitely
|
||||||
|
/// disabling its copy constructor and its assignment operator.
|
||||||
|
///
|
||||||
|
/// To create a non-copyable class, simply inherit from
|
||||||
|
/// sf::NonCopyable.
|
||||||
|
///
|
||||||
|
/// The type of inheritance (public or private) doesn't matter,
|
||||||
|
/// the copy constructor and assignment operator are declared private
|
||||||
|
/// in sf::NonCopyable so they will end up being inaccessible in both
|
||||||
|
/// cases. Thus you can use a shorter syntax for inheriting from it
|
||||||
|
/// (see below).
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// class MyNonCopyableClass : sf::NonCopyable
|
||||||
|
/// {
|
||||||
|
/// ...
|
||||||
|
/// };
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Deciding whether the instances of a class can be copied
|
||||||
|
/// or not is a very important design choice. You are strongly
|
||||||
|
/// encouraged to think about it before writing a class,
|
||||||
|
/// and to use sf::NonCopyable when necessary to prevent
|
||||||
|
/// many potential future errors when using it. This is also
|
||||||
|
/// a very important indication to users of your class.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,543 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_STRING_HPP
|
||||||
|
#define SFML_STRING_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
#include <locale>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Utility string class that automatically handles
|
||||||
|
/// conversions between types and encodings
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_SYSTEM_API String
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
typedef std::basic_string<Uint32>::iterator Iterator; ///< Iterator type
|
||||||
|
typedef std::basic_string<Uint32>::const_iterator ConstIterator; ///< Constant iterator type
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static const std::size_t InvalidPos; ///< Represents an invalid position in the string
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor creates an empty string.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from a single ANSI character and a locale
|
||||||
|
///
|
||||||
|
/// The source character is converted to UTF-32 according
|
||||||
|
/// to the given locale.
|
||||||
|
///
|
||||||
|
/// \param ansiChar ANSI character to convert
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(char ansiChar, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from single wide character
|
||||||
|
///
|
||||||
|
/// \param wideChar Wide character to convert
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(wchar_t wideChar);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from single UTF-32 character
|
||||||
|
///
|
||||||
|
/// \param utf32Char UTF-32 character to convert
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(Uint32 utf32Char);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from a null-terminated C-style ANSI string and a locale
|
||||||
|
///
|
||||||
|
/// The source string is converted to UTF-32 according
|
||||||
|
/// to the given locale.
|
||||||
|
///
|
||||||
|
/// \param ansiString ANSI string to convert
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const char* ansiString, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from an ANSI string and a locale
|
||||||
|
///
|
||||||
|
/// The source string is converted to UTF-32 according
|
||||||
|
/// to the given locale.
|
||||||
|
///
|
||||||
|
/// \param ansiString ANSI string to convert
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const std::string& ansiString, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from null-terminated C-style wide string
|
||||||
|
///
|
||||||
|
/// \param wideString Wide string to convert
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const wchar_t* wideString);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from a wide string
|
||||||
|
///
|
||||||
|
/// \param wideString Wide string to convert
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const std::wstring& wideString);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from a null-terminated C-style UTF-32 string
|
||||||
|
///
|
||||||
|
/// \param utf32String UTF-32 string to assign
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const Uint32* utf32String);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from an UTF-32 string
|
||||||
|
///
|
||||||
|
/// \param utf32String UTF-32 string to assign
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const std::basic_string<Uint32>& utf32String);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy Instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String(const String& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Implicit cast operator to std::string (ANSI string)
|
||||||
|
///
|
||||||
|
/// The current global locale is used for conversion. If you
|
||||||
|
/// want to explicitely specify a locale, see toAnsiString.
|
||||||
|
/// Characters that do not fit in the target encoding are
|
||||||
|
/// discarded from the returned string.
|
||||||
|
/// This operator is defined for convenience, and is equivalent
|
||||||
|
/// to calling toAnsiString().
|
||||||
|
///
|
||||||
|
/// \return Converted ANSI string
|
||||||
|
///
|
||||||
|
/// \see toAnsiString, operator std::wstring
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
operator std::string() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Implicit cast operator to std::wstring (wide string)
|
||||||
|
///
|
||||||
|
/// Characters that do not fit in the target encoding are
|
||||||
|
/// discarded from the returned string.
|
||||||
|
/// This operator is defined for convenience, and is equivalent
|
||||||
|
/// to calling toWideString().
|
||||||
|
///
|
||||||
|
/// \return Converted wide string
|
||||||
|
///
|
||||||
|
/// \see toWideString, operator std::string
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
operator std::wstring() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert the unicode string to an ANSI string
|
||||||
|
///
|
||||||
|
/// The UTF-32 string is converted to an ANSI string in
|
||||||
|
/// the encoding defined by \a locale.
|
||||||
|
/// Characters that do not fit in the target encoding are
|
||||||
|
/// discarded from the returned string.
|
||||||
|
///
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Converted ANSI string
|
||||||
|
///
|
||||||
|
/// \see toWideString, operator std::string
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::string toAnsiString(const std::locale& locale = std::locale()) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert the unicode string to a wide string
|
||||||
|
///
|
||||||
|
/// Characters that do not fit in the target encoding are
|
||||||
|
/// discarded from the returned string.
|
||||||
|
///
|
||||||
|
/// \return Converted wide string
|
||||||
|
///
|
||||||
|
/// \see toAnsiString, operator std::wstring
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::wstring toWideString() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String& operator =(const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of += operator to append an UTF-32 string
|
||||||
|
///
|
||||||
|
/// \param right String to append
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String& operator +=(const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of [] operator to access a character by its position
|
||||||
|
///
|
||||||
|
/// This function provides read-only access to characters.
|
||||||
|
/// Note: this function doesn't throw if \a index is out of range.
|
||||||
|
///
|
||||||
|
/// \param index Index of the character to get
|
||||||
|
///
|
||||||
|
/// \return Character at position \a index
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Uint32 operator [](std::size_t index) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of [] operator to access a character by its position
|
||||||
|
///
|
||||||
|
/// This function provides read and write access to characters.
|
||||||
|
/// Note: this function doesn't throw if \a index is out of range.
|
||||||
|
///
|
||||||
|
/// \param index Index of the character to get
|
||||||
|
///
|
||||||
|
/// \return Reference to the character at position \a index
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Uint32& operator [](std::size_t index);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clear the string
|
||||||
|
///
|
||||||
|
/// This function removes all the characters from the string.
|
||||||
|
///
|
||||||
|
/// \see isEmpty, erase
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the string
|
||||||
|
///
|
||||||
|
/// \return Number of characters in the string
|
||||||
|
///
|
||||||
|
/// \see isEmpty
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::size_t getSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check whether the string is empty or not
|
||||||
|
///
|
||||||
|
/// \return True if the string is empty (i.e. contains no character)
|
||||||
|
///
|
||||||
|
/// \see clear, getSize
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Erase one or more characters from the string
|
||||||
|
///
|
||||||
|
/// This function removes a sequence of \a count characters
|
||||||
|
/// starting from \a position.
|
||||||
|
///
|
||||||
|
/// \param position Position of the first character to erase
|
||||||
|
/// \param count Number of characters to erase
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void erase(std::size_t position, std::size_t count = 1);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Insert one or more characters into the string
|
||||||
|
///
|
||||||
|
/// This function inserts the characters of \a str
|
||||||
|
/// into the string, starting from \a position.
|
||||||
|
///
|
||||||
|
/// \param position Position of insertion
|
||||||
|
/// \param str Characters to insert
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void insert(std::size_t position, const String& str);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Find a sequence of one or more characters in the string
|
||||||
|
///
|
||||||
|
/// This function searches for the characters of \a str
|
||||||
|
/// into the string, starting from \a start.
|
||||||
|
///
|
||||||
|
/// \param str Characters to find
|
||||||
|
/// \param start Where to begin searching
|
||||||
|
///
|
||||||
|
/// \return Position of \a str in the string, or String::InvalidPos if not found
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::size_t find(const String& str, std::size_t start = 0) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a pointer to the C-style array of characters
|
||||||
|
///
|
||||||
|
/// This functions provides a read-only access to a
|
||||||
|
/// null-terminated C-style representation of the string.
|
||||||
|
/// The returned pointer is temporary and is meant only for
|
||||||
|
/// immediate use, thus it is not recommended to store it.
|
||||||
|
///
|
||||||
|
/// \return Read-only pointer to the array of characters
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
const Uint32* getData() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return an iterator to the beginning of the string
|
||||||
|
///
|
||||||
|
/// \return Read-write iterator to the beginning of the string characters
|
||||||
|
///
|
||||||
|
/// \see end
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Iterator begin();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return an iterator to the beginning of the string
|
||||||
|
///
|
||||||
|
/// \return Read-only iterator to the beginning of the string characters
|
||||||
|
///
|
||||||
|
/// \see end
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
ConstIterator begin() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return an iterator to the beginning of the string
|
||||||
|
///
|
||||||
|
/// The end iterator refers to 1 position past the last character;
|
||||||
|
/// thus it represents an invalid character and should never be
|
||||||
|
/// accessed.
|
||||||
|
///
|
||||||
|
/// \return Read-write iterator to the end of the string characters
|
||||||
|
///
|
||||||
|
/// \see begin
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Iterator end();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return an iterator to the beginning of the string
|
||||||
|
///
|
||||||
|
/// The end iterator refers to 1 position past the last character;
|
||||||
|
/// thus it represents an invalid character and should never be
|
||||||
|
/// accessed.
|
||||||
|
///
|
||||||
|
/// \return Read-only iterator to the end of the string characters
|
||||||
|
///
|
||||||
|
/// \see begin
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
ConstIterator end() const;
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
friend SFML_SYSTEM_API bool operator ==(const String& left, const String& right);
|
||||||
|
friend SFML_SYSTEM_API bool operator <(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::basic_string<Uint32> m_string; ///< Internal string of UTF-32 characters
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of == operator to compare two UTF-32 strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return True if both strings are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator ==(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of != operator to compare two UTF-32 strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return True if both strings are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator !=(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of < operator to compare two UTF-32 strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is alphabetically lesser than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator <(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of > operator to compare two UTF-32 strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is alphabetically greater than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator >(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of <= operator to compare two UTF-32 strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is alphabetically lesser or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator <=(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of >= operator to compare two UTF-32 strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is alphabetically greater or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator >=(const String& left, const String& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates String
|
||||||
|
/// \brief Overload of binary + operator to concatenate two strings
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a string)
|
||||||
|
/// \param right Right operand (a string)
|
||||||
|
///
|
||||||
|
/// \return Concatenated string
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API String operator +(const String& left, const String& right);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_STRING_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::String
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// sf::String is a utility string class defined mainly for
|
||||||
|
/// convenience. It is a Unicode string (implemented using
|
||||||
|
/// UTF-32), thus it can store any character in the world
|
||||||
|
/// (european, chinese, arabic, hebrew, etc.).
|
||||||
|
///
|
||||||
|
/// It automatically handles conversions from/to ANSI and
|
||||||
|
/// wide strings, so that you can work with standard string
|
||||||
|
/// classes and still be compatible with functions taking a
|
||||||
|
/// sf::String.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// sf::String s;
|
||||||
|
///
|
||||||
|
/// std::string s1 = s; // automatically converted to ANSI string
|
||||||
|
/// std::wstring s2 = s; // automatically converted to wide string
|
||||||
|
/// s = "hello"; // automatically converted from ANSI string
|
||||||
|
/// s = L"hello"; // automatically converted from wide string
|
||||||
|
/// s += 'a'; // automatically converted from ANSI string
|
||||||
|
/// s += L'a'; // automatically converted from wide string
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Conversions involving ANSI strings use the default user locale. However
|
||||||
|
/// it is possible to use a custom locale if necessary:
|
||||||
|
/// \code
|
||||||
|
/// std::locale locale;
|
||||||
|
/// sf::String s;
|
||||||
|
/// ...
|
||||||
|
/// std::string s1 = s.toAnsiString(locale);
|
||||||
|
/// s = sf::String("hello", locale);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// sf::String defines the most important functions of the
|
||||||
|
/// standard std::string class: removing, random access, iterating,
|
||||||
|
/// appending, comparing, etc. However it is a simple class
|
||||||
|
/// provided for convenience, and you may have to consider using
|
||||||
|
/// a more optimized class if your program requires complex string
|
||||||
|
/// handling. The automatic conversion functions will then take
|
||||||
|
/// care of converting your string to sf::String whenever SFML
|
||||||
|
/// requires it.
|
||||||
|
///
|
||||||
|
/// Please note that SFML also defines a low-level, generic
|
||||||
|
/// interface for Unicode handling, see the sf::Utf classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,452 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_TIME_HPP
|
||||||
|
#define SFML_TIME_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Represents a time value
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_SYSTEM_API Time
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Sets the time value to zero.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the time value as a number of seconds
|
||||||
|
///
|
||||||
|
/// \return Time in seconds
|
||||||
|
///
|
||||||
|
/// \see asMilliseconds, asMicroseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
float asSeconds() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the time value as a number of milliseconds
|
||||||
|
///
|
||||||
|
/// \return Time in milliseconds
|
||||||
|
///
|
||||||
|
/// \see asSeconds, asMicroseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Int32 asMilliseconds() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the time value as a number of microseconds
|
||||||
|
///
|
||||||
|
/// \return Time in microseconds
|
||||||
|
///
|
||||||
|
/// \see asSeconds, asMilliseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Int64 asMicroseconds() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static const Time Zero; ///< Predefined "zero" time value
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
friend SFML_SYSTEM_API Time seconds(float);
|
||||||
|
friend SFML_SYSTEM_API Time milliseconds(Int32);
|
||||||
|
friend SFML_SYSTEM_API Time microseconds(Int64);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from a number of microseconds
|
||||||
|
///
|
||||||
|
/// This function is internal. To construct time values,
|
||||||
|
/// use sf::seconds, sf::milliseconds or sf::microseconds instead.
|
||||||
|
///
|
||||||
|
/// \param microseconds Number of microseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Time(Int64 microseconds);
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Int64 m_microseconds; ///< Time value stored as microseconds
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Construct a time value from a number of seconds
|
||||||
|
///
|
||||||
|
/// \param amount Number of seconds
|
||||||
|
///
|
||||||
|
/// \return Time value constructed from the amount of seconds
|
||||||
|
///
|
||||||
|
/// \see milliseconds, microseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time seconds(float amount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Construct a time value from a number of milliseconds
|
||||||
|
///
|
||||||
|
/// \param amount Number of milliseconds
|
||||||
|
///
|
||||||
|
/// \return Time value constructed from the amount of milliseconds
|
||||||
|
///
|
||||||
|
/// \see seconds, microseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time milliseconds(Int32 amount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Construct a time value from a number of microseconds
|
||||||
|
///
|
||||||
|
/// \param amount Number of microseconds
|
||||||
|
///
|
||||||
|
/// \return Time value constructed from the amount of microseconds
|
||||||
|
///
|
||||||
|
/// \see seconds, milliseconds
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time microseconds(Int64 amount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of == operator to compare two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return True if both time values are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator ==(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of != operator to compare two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return True if both time values are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator !=(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of < operator to compare two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is lesser than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator <(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of > operator to compare two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is greater than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator >(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of <= operator to compare two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is lesser or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator <=(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of >= operator to compare two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return True if \a left is greater or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API bool operator >=(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of unary - operator to negate a time value
|
||||||
|
///
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return Opposite of the time value
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator -(Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary + operator to add two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return Sum of the two times values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator +(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary += operator to add/assign two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return Sum of the two times values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time& operator +=(Time& left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary - operator to subtract two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return Difference of the two times values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator -(Time left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary -= operator to subtract/assign two time values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return Difference of the two times values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time& operator -=(Time& left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary * operator to scale a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left multiplied by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator *(Time left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary * operator to scale a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left multiplied by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator *(Time left, Int64 right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary * operator to scale a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a number)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return \a left multiplied by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator *(float left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary * operator to scale a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a number)
|
||||||
|
/// \param right Right operand (a time)
|
||||||
|
///
|
||||||
|
/// \return \a left multiplied by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator *(Int64 left, Time right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary *= operator to scale/assign a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left multiplied by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time& operator *=(Time& left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary *= operator to scale/assign a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left multiplied by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time& operator *=(Time& left, Int64 right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary / operator to scale a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left divided by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator /(Time left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary / operator to scale a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left divided by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time operator /(Time left, Int64 right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary /= operator to scale/assign a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left divided by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time& operator /=(Time& left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Time
|
||||||
|
/// \brief Overload of binary /= operator to scale/assign a time value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a time)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return \a left divided by \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_SYSTEM_API Time& operator /=(Time& left, Int64 right);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_TIME_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Time
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// sf::Time encapsulates a time value in a flexible way.
|
||||||
|
/// It allows to define a time value either as a number of
|
||||||
|
/// seconds, milliseconds or microseconds. It also works the
|
||||||
|
/// other way round: you can read a time value as either
|
||||||
|
/// a number of seconds, milliseconds or microseconds.
|
||||||
|
///
|
||||||
|
/// By using such a flexible interface, the API doesn't
|
||||||
|
/// impose any fixed type or resolution for time values,
|
||||||
|
/// and let the user choose its own favorite representation.
|
||||||
|
///
|
||||||
|
/// Time values support the usual mathematical operations:
|
||||||
|
/// you can add or subtract two times, multiply or divide
|
||||||
|
/// a time by a number, compare two times, etc.
|
||||||
|
///
|
||||||
|
/// Since they represent a time span and not an absolute time
|
||||||
|
/// value, times can also be negative.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::Time t1 = sf::seconds(0.1f);
|
||||||
|
/// Int32 milli = t1.asMilliseconds(); // 100
|
||||||
|
///
|
||||||
|
/// sf::Time t2 = sf::milliseconds(30);
|
||||||
|
/// Int64 micro = t2.asMicroseconds(); // 30000
|
||||||
|
///
|
||||||
|
/// sf::Time t3 = sf::microseconds(-800000);
|
||||||
|
/// float sec = t3.asSeconds(); // -0.8
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// void update(sf::Time elapsed)
|
||||||
|
/// {
|
||||||
|
/// position += speed * elapsed.asSeconds();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// update(sf::milliseconds(100));
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see sf::Clock
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,763 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SFML_UTF_HPP
|
||||||
|
#define SFML_UTF_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <locale>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
template <unsigned int N>
|
||||||
|
class Utf;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialization of the Utf template for UTF-8
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <>
|
||||||
|
class Utf<8>
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Decode a single UTF-8 character
|
||||||
|
///
|
||||||
|
/// Decoding a character means finding its unique 32-bits
|
||||||
|
/// code (called the codepoint) in the Unicode standard.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Codepoint of the decoded UTF-8 character
|
||||||
|
/// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static In decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Encode a single UTF-8 character
|
||||||
|
///
|
||||||
|
/// Encoding a character means converting a unique 32-bits
|
||||||
|
/// code (called the codepoint) in the target encoding, UTF-8.
|
||||||
|
///
|
||||||
|
/// \param input Codepoint to encode as UTF-8
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to UTF-8 (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
static Out encode(Uint32 input, Out output, Uint8 replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Advance to the next UTF-8 character
|
||||||
|
///
|
||||||
|
/// This function is necessary for multi-elements encodings, as
|
||||||
|
/// a single character may use more than 1 storage element.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static In next(In begin, In end);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Count the number of characters of a UTF-8 sequence
|
||||||
|
///
|
||||||
|
/// This function is necessary for multi-elements encodings, as
|
||||||
|
/// a single character may use more than 1 storage element, thus the
|
||||||
|
/// total size can be different from (begin - end).
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static std::size_t count(In begin, In end);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an ANSI characters range to UTF-8
|
||||||
|
///
|
||||||
|
/// The current global locale will be used by default, unless you
|
||||||
|
/// pass a custom one in the \a locale parameter.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a wide characters range to UTF-8
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromWide(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-8
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromLatin1(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-8 characters range to ANSI characters
|
||||||
|
///
|
||||||
|
/// The current global locale will be used by default, unless you
|
||||||
|
/// pass a custom one in the \a locale parameter.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-8 characters range to wide characters
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toWide(In begin, In end, Out output, wchar_t replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-8 characters range to latin-1 (ISO-5589-1) characters
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toLatin1(In begin, In end, Out output, char replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-8 characters range to UTF-8
|
||||||
|
///
|
||||||
|
/// This functions does nothing more than a direct copy;
|
||||||
|
/// it is defined only to provide the same interface as other
|
||||||
|
/// specializations of the sf::Utf<> template, and allow
|
||||||
|
/// generic code to be written on top of it.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf8(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-8 characters range to UTF-16
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf16(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-8 characters range to UTF-32
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf32(In begin, In end, Out output);
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialization of the Utf template for UTF-16
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <>
|
||||||
|
class Utf<16>
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Decode a single UTF-16 character
|
||||||
|
///
|
||||||
|
/// Decoding a character means finding its unique 32-bits
|
||||||
|
/// code (called the codepoint) in the Unicode standard.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Codepoint of the decoded UTF-16 character
|
||||||
|
/// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static In decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Encode a single UTF-16 character
|
||||||
|
///
|
||||||
|
/// Encoding a character means converting a unique 32-bits
|
||||||
|
/// code (called the codepoint) in the target encoding, UTF-16.
|
||||||
|
///
|
||||||
|
/// \param input Codepoint to encode as UTF-16
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to UTF-16 (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
static Out encode(Uint32 input, Out output, Uint16 replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Advance to the next UTF-16 character
|
||||||
|
///
|
||||||
|
/// This function is necessary for multi-elements encodings, as
|
||||||
|
/// a single character may use more than 1 storage element.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static In next(In begin, In end);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Count the number of characters of a UTF-16 sequence
|
||||||
|
///
|
||||||
|
/// This function is necessary for multi-elements encodings, as
|
||||||
|
/// a single character may use more than 1 storage element, thus the
|
||||||
|
/// total size can be different from (begin - end).
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static std::size_t count(In begin, In end);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an ANSI characters range to UTF-16
|
||||||
|
///
|
||||||
|
/// The current global locale will be used by default, unless you
|
||||||
|
/// pass a custom one in the \a locale parameter.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a wide characters range to UTF-16
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromWide(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-16
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromLatin1(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-16 characters range to ANSI characters
|
||||||
|
///
|
||||||
|
/// The current global locale will be used by default, unless you
|
||||||
|
/// pass a custom one in the \a locale parameter.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-16 characters range to wide characters
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toWide(In begin, In end, Out output, wchar_t replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toLatin1(In begin, In end, Out output, char replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-16 characters range to UTF-8
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf8(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-16 characters range to UTF-16
|
||||||
|
///
|
||||||
|
/// This functions does nothing more than a direct copy;
|
||||||
|
/// it is defined only to provide the same interface as other
|
||||||
|
/// specializations of the sf::Utf<> template, and allow
|
||||||
|
/// generic code to be written on top of it.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf16(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-16 characters range to UTF-32
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf32(In begin, In end, Out output);
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialization of the Utf template for UTF-32
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <>
|
||||||
|
class Utf<32>
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Decode a single UTF-32 character
|
||||||
|
///
|
||||||
|
/// Decoding a character means finding its unique 32-bits
|
||||||
|
/// code (called the codepoint) in the Unicode standard.
|
||||||
|
/// For UTF-32, the character value is the same as the codepoint.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Codepoint of the decoded UTF-32 character
|
||||||
|
/// \param replacement Replacement character to use in case the UTF-8 sequence is invalid
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static In decode(In begin, In end, Uint32& output, Uint32 replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Encode a single UTF-32 character
|
||||||
|
///
|
||||||
|
/// Encoding a character means converting a unique 32-bits
|
||||||
|
/// code (called the codepoint) in the target encoding, UTF-32.
|
||||||
|
/// For UTF-32, the codepoint is the same as the character value.
|
||||||
|
///
|
||||||
|
/// \param input Codepoint to encode as UTF-32
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to UTF-32 (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
static Out encode(Uint32 input, Out output, Uint32 replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Advance to the next UTF-32 character
|
||||||
|
///
|
||||||
|
/// This function is trivial for UTF-32, which can store
|
||||||
|
/// every character in a single storage element.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static In next(In begin, In end);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Count the number of characters of a UTF-32 sequence
|
||||||
|
///
|
||||||
|
/// This function is trivial for UTF-32, which can store
|
||||||
|
/// every character in a single storage element.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator pointing to one past the last read element of the input sequence
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static std::size_t count(In begin, In end);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an ANSI characters range to UTF-32
|
||||||
|
///
|
||||||
|
/// The current global locale will be used by default, unless you
|
||||||
|
/// pass a custom one in the \a locale parameter.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromAnsi(In begin, In end, Out output, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a wide characters range to UTF-32
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromWide(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a latin-1 (ISO-5589-1) characters range to UTF-32
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out fromLatin1(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-32 characters range to ANSI characters
|
||||||
|
///
|
||||||
|
/// The current global locale will be used by default, unless you
|
||||||
|
/// pass a custom one in the \a locale parameter.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to ANSI (use 0 to skip them)
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toAnsi(In begin, In end, Out output, char replacement = 0, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-32 characters range to wide characters
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toWide(In begin, In end, Out output, wchar_t replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert an UTF-16 characters range to latin-1 (ISO-5589-1) characters
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement for characters not convertible to wide (use 0 to skip them)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toLatin1(In begin, In end, Out output, char replacement = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-32 characters range to UTF-8
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf8(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-32 characters range to UTF-16
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf16(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a UTF-32 characters range to UTF-32
|
||||||
|
///
|
||||||
|
/// This functions does nothing more than a direct copy;
|
||||||
|
/// it is defined only to provide the same interface as other
|
||||||
|
/// specializations of the sf::Utf<> template, and allow
|
||||||
|
/// generic code to be written on top of it.
|
||||||
|
///
|
||||||
|
/// \param begin Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param end Iterator pointing to the end of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
static Out toUtf32(In begin, In end, Out output);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Decode a single ANSI character to UTF-32
|
||||||
|
///
|
||||||
|
/// This function does not exist in other specializations
|
||||||
|
/// of sf::Utf<>, it is defined for convenience (it is used by
|
||||||
|
/// several other conversion functions).
|
||||||
|
///
|
||||||
|
/// \param input Input ANSI character
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Converted character
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static Uint32 decodeAnsi(In input, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Decode a single wide character to UTF-32
|
||||||
|
///
|
||||||
|
/// This function does not exist in other specializations
|
||||||
|
/// of sf::Utf<>, it is defined for convenience (it is used by
|
||||||
|
/// several other conversion functions).
|
||||||
|
///
|
||||||
|
/// \param input Input wide character
|
||||||
|
///
|
||||||
|
/// \return Converted character
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
static Uint32 decodeWide(In input);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Encode a single UTF-32 character to ANSI
|
||||||
|
///
|
||||||
|
/// This function does not exist in other specializations
|
||||||
|
/// of sf::Utf<>, it is defined for convenience (it is used by
|
||||||
|
/// several other conversion functions).
|
||||||
|
///
|
||||||
|
/// \param codepoint Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement if the input character is not convertible to ANSI (use 0 to skip it)
|
||||||
|
/// \param locale Locale to use for conversion
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
static Out encodeAnsi(Uint32 codepoint, Out output, char replacement = 0, const std::locale& locale = std::locale());
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Encode a single UTF-32 character to wide
|
||||||
|
///
|
||||||
|
/// This function does not exist in other specializations
|
||||||
|
/// of sf::Utf<>, it is defined for convenience (it is used by
|
||||||
|
/// several other conversion functions).
|
||||||
|
///
|
||||||
|
/// \param codepoint Iterator pointing to the beginning of the input sequence
|
||||||
|
/// \param output Iterator pointing to the beginning of the output sequence
|
||||||
|
/// \param replacement Replacement if the input character is not convertible to wide (use 0 to skip it)
|
||||||
|
///
|
||||||
|
/// \return Iterator to the end of the output sequence which has been written
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
static Out encodeWide(Uint32 codepoint, Out output, wchar_t replacement = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <SFML/System/Utf.inl>
|
||||||
|
|
||||||
|
// Make typedefs to get rid of the template syntax
|
||||||
|
typedef Utf<8> Utf8;
|
||||||
|
typedef Utf<16> Utf16;
|
||||||
|
typedef Utf<32> Utf32;
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_UTF_HPP
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Utf
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// Utility class providing generic functions for UTF conversions.
|
||||||
|
///
|
||||||
|
/// sf::Utf is a low-level, generic interface for counting, iterating,
|
||||||
|
/// encoding and decoding Unicode characters and strings. It is able
|
||||||
|
/// to handle ANSI, wide, latin-1, UTF-8, UTF-16 and UTF-32 encodings.
|
||||||
|
///
|
||||||
|
/// sf::Utf<X> functions are all static, these classes are not meant to
|
||||||
|
/// be instanciated. All the functions are template, so that you
|
||||||
|
/// can use any character / string type for a given encoding.
|
||||||
|
///
|
||||||
|
/// It has 3 specializations:
|
||||||
|
/// \li sf::Utf<8> (typedef'd to sf::Utf8)
|
||||||
|
/// \li sf::Utf<16> (typedef'd to sf::Utf16)
|
||||||
|
/// \li sf::Utf<32> (typedef'd to sf::Utf32)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,752 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// References :
|
||||||
|
//
|
||||||
|
// http://www.unicode.org/
|
||||||
|
// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c
|
||||||
|
// http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.h
|
||||||
|
// http://people.w3.org/rishida/scripts/uniview/conversion
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
In Utf<8>::decode(In begin, In end, Uint32& output, Uint32 replacement)
|
||||||
|
{
|
||||||
|
// Some useful precomputed data
|
||||||
|
static const int trailing[256] =
|
||||||
|
{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
|
||||||
|
};
|
||||||
|
static const Uint32 offsets[6] =
|
||||||
|
{
|
||||||
|
0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080
|
||||||
|
};
|
||||||
|
|
||||||
|
// decode the character
|
||||||
|
int trailingBytes = trailing[static_cast<Uint8>(*begin)];
|
||||||
|
if (begin + trailingBytes < end)
|
||||||
|
{
|
||||||
|
output = 0;
|
||||||
|
switch (trailingBytes)
|
||||||
|
{
|
||||||
|
case 5 : output += static_cast<Uint8>(*begin++); output <<= 6;
|
||||||
|
case 4 : output += static_cast<Uint8>(*begin++); output <<= 6;
|
||||||
|
case 3 : output += static_cast<Uint8>(*begin++); output <<= 6;
|
||||||
|
case 2 : output += static_cast<Uint8>(*begin++); output <<= 6;
|
||||||
|
case 1 : output += static_cast<Uint8>(*begin++); output <<= 6;
|
||||||
|
case 0 : output += static_cast<Uint8>(*begin++);
|
||||||
|
}
|
||||||
|
output -= offsets[trailingBytes];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Incomplete character
|
||||||
|
begin = end;
|
||||||
|
output = replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
Out Utf<8>::encode(Uint32 input, Out output, Uint8 replacement)
|
||||||
|
{
|
||||||
|
// Some useful precomputed data
|
||||||
|
static const Uint8 firstBytes[7] =
|
||||||
|
{
|
||||||
|
0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
|
||||||
|
};
|
||||||
|
|
||||||
|
// encode the character
|
||||||
|
if ((input > 0x0010FFFF) || ((input >= 0xD800) && (input <= 0xDBFF)))
|
||||||
|
{
|
||||||
|
// Invalid character
|
||||||
|
if (replacement)
|
||||||
|
*output++ = replacement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Valid character
|
||||||
|
|
||||||
|
// Get the number of bytes to write
|
||||||
|
std::size_t bytestoWrite = 1;
|
||||||
|
if (input < 0x80) bytestoWrite = 1;
|
||||||
|
else if (input < 0x800) bytestoWrite = 2;
|
||||||
|
else if (input < 0x10000) bytestoWrite = 3;
|
||||||
|
else if (input <= 0x0010FFFF) bytestoWrite = 4;
|
||||||
|
|
||||||
|
// Extract the bytes to write
|
||||||
|
Uint8 bytes[4];
|
||||||
|
switch (bytestoWrite)
|
||||||
|
{
|
||||||
|
case 4 : bytes[3] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
|
||||||
|
case 3 : bytes[2] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
|
||||||
|
case 2 : bytes[1] = static_cast<Uint8>((input | 0x80) & 0xBF); input >>= 6;
|
||||||
|
case 1 : bytes[0] = static_cast<Uint8> (input | firstBytes[bytestoWrite]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add them to the output
|
||||||
|
output = std::copy(bytes, bytes + bytestoWrite, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
In Utf<8>::next(In begin, In end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
return decode(begin, end, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
std::size_t Utf<8>::count(In begin, In end)
|
||||||
|
{
|
||||||
|
std::size_t length = 0;
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
begin = next(begin, end);
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::fromAnsi(In begin, In end, Out output, const std::locale& locale)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint = Utf<32>::decodeAnsi(*begin++, locale);
|
||||||
|
output = encode(codepoint, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::fromWide(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint = Utf<32>::decodeWide(*begin++);
|
||||||
|
output = encode(codepoint, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::fromLatin1(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
// Latin-1 is directly compatible with Unicode encodings,
|
||||||
|
// and can thus be treated as (a sub-range of) UTF-32
|
||||||
|
while (begin < end)
|
||||||
|
output = encode(*begin++, output);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::toAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
output = Utf<32>::encodeAnsi(codepoint, output, replacement, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::toWide(In begin, In end, Out output, wchar_t replacement)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
output = Utf<32>::encodeWide(codepoint, output, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::toLatin1(In begin, In end, Out output, char replacement)
|
||||||
|
{
|
||||||
|
// Latin-1 is directly compatible with Unicode encodings,
|
||||||
|
// and can thus be treated as (a sub-range of) UTF-32
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
*output++ = codepoint < 256 ? static_cast<char>(codepoint) : replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::toUtf8(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
return std::copy(begin, end, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::toUtf16(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
output = Utf<16>::encode(codepoint, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<8>::toUtf32(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
*output++ = codepoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
In Utf<16>::decode(In begin, In end, Uint32& output, Uint32 replacement)
|
||||||
|
{
|
||||||
|
Uint16 first = *begin++;
|
||||||
|
|
||||||
|
// If it's a surrogate pair, first convert to a single UTF-32 character
|
||||||
|
if ((first >= 0xD800) && (first <= 0xDBFF))
|
||||||
|
{
|
||||||
|
if (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 second = *begin++;
|
||||||
|
if ((second >= 0xDC00) && (second <= 0xDFFF))
|
||||||
|
{
|
||||||
|
// The second element is valid: convert the two elements to a UTF-32 character
|
||||||
|
output = static_cast<Uint32>(((first - 0xD800) << 10) + (second - 0xDC00) + 0x0010000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid character
|
||||||
|
output = replacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid character
|
||||||
|
begin = end;
|
||||||
|
output = replacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We can make a direct copy
|
||||||
|
output = first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
Out Utf<16>::encode(Uint32 input, Out output, Uint16 replacement)
|
||||||
|
{
|
||||||
|
if (input < 0xFFFF)
|
||||||
|
{
|
||||||
|
// The character can be copied directly, we just need to check if it's in the valid range
|
||||||
|
if ((input >= 0xD800) && (input <= 0xDFFF))
|
||||||
|
{
|
||||||
|
// Invalid character (this range is reserved)
|
||||||
|
if (replacement)
|
||||||
|
*output++ = replacement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Valid character directly convertible to a single UTF-16 character
|
||||||
|
*output++ = static_cast<Uint16>(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (input > 0x0010FFFF)
|
||||||
|
{
|
||||||
|
// Invalid character (greater than the maximum unicode value)
|
||||||
|
if (replacement)
|
||||||
|
*output++ = replacement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The input character will be converted to two UTF-16 elements
|
||||||
|
input -= 0x0010000;
|
||||||
|
*output++ = static_cast<Uint16>((input >> 10) + 0xD800);
|
||||||
|
*output++ = static_cast<Uint16>((input & 0x3FFUL) + 0xDC00);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
In Utf<16>::next(In begin, In end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
return decode(begin, end, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
std::size_t Utf<16>::count(In begin, In end)
|
||||||
|
{
|
||||||
|
std::size_t length = 0;
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
begin = next(begin, end);
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::fromAnsi(In begin, In end, Out output, const std::locale& locale)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint = Utf<32>::decodeAnsi(*begin++, locale);
|
||||||
|
output = encode(codepoint, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::fromWide(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint = Utf<32>::decodeWide(*begin++);
|
||||||
|
output = encode(codepoint, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::fromLatin1(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
// Latin-1 is directly compatible with Unicode encodings,
|
||||||
|
// and can thus be treated as (a sub-range of) UTF-32
|
||||||
|
return std::copy(begin, end, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::toAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
output = Utf<32>::encodeAnsi(codepoint, output, replacement, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::toWide(In begin, In end, Out output, wchar_t replacement)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
output = Utf<32>::encodeWide(codepoint, output, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::toLatin1(In begin, In end, Out output, char replacement)
|
||||||
|
{
|
||||||
|
// Latin-1 is directly compatible with Unicode encodings,
|
||||||
|
// and can thus be treated as (a sub-range of) UTF-32
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
*output++ = *begin < 256 ? static_cast<char>(*begin) : replacement;
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::toUtf8(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
output = Utf<8>::encode(codepoint, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::toUtf16(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
return std::copy(begin, end, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<16>::toUtf32(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
Uint32 codepoint;
|
||||||
|
begin = decode(begin, end, codepoint);
|
||||||
|
*output++ = codepoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
In Utf<32>::decode(In begin, In /*end*/, Uint32& output, Uint32 /*replacement*/)
|
||||||
|
{
|
||||||
|
output = *begin++;
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
Out Utf<32>::encode(Uint32 input, Out output, Uint32 /*replacement*/)
|
||||||
|
{
|
||||||
|
*output++ = input;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
In Utf<32>::next(In begin, In /*end*/)
|
||||||
|
{
|
||||||
|
return ++begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
std::size_t Utf<32>::count(In begin, In end)
|
||||||
|
{
|
||||||
|
return begin - end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::fromAnsi(In begin, In end, Out output, const std::locale& locale)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
*output++ = decodeAnsi(*begin++, locale);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::fromWide(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
*output++ = decodeWide(*begin++);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::fromLatin1(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
// Latin-1 is directly compatible with Unicode encodings,
|
||||||
|
// and can thus be treated as (a sub-range of) UTF-32
|
||||||
|
return std::copy(begin, end, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::toAnsi(In begin, In end, Out output, char replacement, const std::locale& locale)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
output = encodeAnsi(*begin++, output, replacement, locale);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::toWide(In begin, In end, Out output, wchar_t replacement)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
output = encodeWide(*begin++, output, replacement);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::toLatin1(In begin, In end, Out output, char replacement)
|
||||||
|
{
|
||||||
|
// Latin-1 is directly compatible with Unicode encodings,
|
||||||
|
// and can thus be treated as (a sub-range of) UTF-32
|
||||||
|
while (begin < end)
|
||||||
|
{
|
||||||
|
*output++ = *begin < 256 ? static_cast<char>(*begin) : replacement;
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::toUtf8(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
output = Utf<8>::encode(*begin++, output);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::toUtf16(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
while (begin < end)
|
||||||
|
output = Utf<16>::encode(*begin++, output);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In, typename Out>
|
||||||
|
Out Utf<32>::toUtf32(In begin, In end, Out output)
|
||||||
|
{
|
||||||
|
return std::copy(begin, end, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
Uint32 Utf<32>::decodeAnsi(In input, const std::locale& locale)
|
||||||
|
{
|
||||||
|
// On Windows, gcc's standard library (glibc++) has almost
|
||||||
|
// no support for Unicode stuff. As a consequence, in this
|
||||||
|
// context we can only use the default locale and ignore
|
||||||
|
// the one passed as parameter.
|
||||||
|
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS) && /* if Windows ... */ \
|
||||||
|
(defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \
|
||||||
|
!(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */
|
||||||
|
|
||||||
|
(void)locale; // to avoid warnings
|
||||||
|
|
||||||
|
wchar_t character = 0;
|
||||||
|
mbtowc(&character, &input, 1);
|
||||||
|
return static_cast<Uint32>(character);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Get the facet of the locale which deals with character conversion
|
||||||
|
const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
|
||||||
|
|
||||||
|
// Use the facet to convert each character of the input string
|
||||||
|
return static_cast<Uint32>(facet.widen(input));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename In>
|
||||||
|
Uint32 Utf<32>::decodeWide(In input)
|
||||||
|
{
|
||||||
|
// The encoding of wide characters is not well defined and is left to the system;
|
||||||
|
// however we can safely assume that it is UCS-2 on Windows and
|
||||||
|
// UCS-4 on Unix systems.
|
||||||
|
// In both cases, a simple copy is enough (UCS-2 is a subset of UCS-4,
|
||||||
|
// and UCS-4 *is* UTF-32).
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
Out Utf<32>::encodeAnsi(Uint32 codepoint, Out output, char replacement, const std::locale& locale)
|
||||||
|
{
|
||||||
|
// On Windows, gcc's standard library (glibc++) has almost
|
||||||
|
// no support for Unicode stuff. As a consequence, in this
|
||||||
|
// context we can only use the default locale and ignore
|
||||||
|
// the one passed as parameter.
|
||||||
|
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS) && /* if Windows ... */ \
|
||||||
|
(defined(__GLIBCPP__) || defined (__GLIBCXX__)) && /* ... and standard library is glibc++ ... */ \
|
||||||
|
!(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) /* ... and STLPort is not used on top of it */
|
||||||
|
|
||||||
|
(void)locale; // to avoid warnings
|
||||||
|
|
||||||
|
char character = 0;
|
||||||
|
if (wctomb(&character, static_cast<wchar_t>(codepoint)) >= 0)
|
||||||
|
*output++ = character;
|
||||||
|
else if (replacement)
|
||||||
|
*output++ = replacement;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Get the facet of the locale which deals with character conversion
|
||||||
|
const std::ctype<wchar_t>& facet = std::use_facet< std::ctype<wchar_t> >(locale);
|
||||||
|
|
||||||
|
// Use the facet to convert each character of the input string
|
||||||
|
*output++ = facet.narrow(static_cast<wchar_t>(codepoint), replacement);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename Out>
|
||||||
|
Out Utf<32>::encodeWide(Uint32 codepoint, Out output, wchar_t replacement)
|
||||||
|
{
|
||||||
|
// The encoding of wide characters is not well defined and is left to the system;
|
||||||
|
// however we can safely assume that it is UCS-2 on Windows and
|
||||||
|
// UCS-4 on Unix systems.
|
||||||
|
// For UCS-2 we need to check if the source characters fits in (UCS-2 is a subset of UCS-4).
|
||||||
|
// For UCS-4 we can do a direct copy (UCS-4 *is* UTF-32).
|
||||||
|
|
||||||
|
switch (sizeof(wchar_t))
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
*output++ = static_cast<wchar_t>(codepoint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if ((codepoint <= 0xFFFF) && ((codepoint < 0xD800) || (codepoint > 0xDFFF)))
|
||||||
|
{
|
||||||
|
*output++ = static_cast<wchar_t>(codepoint);
|
||||||
|
}
|
||||||
|
else if (replacement)
|
||||||
|
{
|
||||||
|
*output++ = replacement;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
SFML
|
||||||
|
----
|
||||||
|
|
||||||
|
SFML - Copyright (C) 2007-2013 Laurent Gomila - laurent.gom@gmail.com
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or
|
||||||
|
implied warranty. In no event will the authors be held
|
||||||
|
liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute
|
||||||
|
it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented;
|
||||||
|
you must not claim that you wrote the original software.
|
||||||
|
If you use this software in a product, an acknowledgment
|
||||||
|
in the product documentation would be appreciated but
|
||||||
|
is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such,
|
||||||
|
and must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any
|
||||||
|
source distribution.
|
|
@ -1,712 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/Ftp.hpp>
|
|
||||||
#include <SFML/Network/IPAddress.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iterator>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Utility class for exchanging stuff with the server
|
|
||||||
// on the data channel
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
class Ftp::DataChannel : NonCopyable
|
|
||||||
{
|
|
||||||
public :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
DataChannel(Ftp& Owner);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Destructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
~DataChannel();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Open the data channel using the specified mode and port
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Open(Ftp::TransferMode Mode);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Send data on the data channel
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Send(const std::vector<char>& Data);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Receive data on the data channel until it is closed
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Receive(std::vector<char>& Data);
|
|
||||||
|
|
||||||
private :
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Member data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp& myFtp; ///< Reference to the owner Ftp instance
|
|
||||||
SocketTCP myDataSocket; ///< Socket used for data transfers
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response::Response(Status Code, const std::string& Message) :
|
|
||||||
myStatus (Code),
|
|
||||||
myMessage(Message)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Convenience function to check if the response status code
|
|
||||||
/// means a success
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Ftp::Response::IsOk() const
|
|
||||||
{
|
|
||||||
return myStatus < 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the response status code
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response::Status Ftp::Response::GetStatus() const
|
|
||||||
{
|
|
||||||
return myStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the full message contained in the response
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& Ftp::Response::GetMessage() const
|
|
||||||
{
|
|
||||||
return myMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response Resp) :
|
|
||||||
Ftp::Response(Resp)
|
|
||||||
{
|
|
||||||
if (IsOk())
|
|
||||||
{
|
|
||||||
// Extract the directory from the server response
|
|
||||||
std::string::size_type Begin = Resp.GetMessage().find('"', 0);
|
|
||||||
std::string::size_type End = Resp.GetMessage().find('"', Begin + 1);
|
|
||||||
myDirectory = Resp.GetMessage().substr(Begin + 1, End - Begin - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the directory returned in the response
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& Ftp::DirectoryResponse::GetDirectory() const
|
|
||||||
{
|
|
||||||
return myDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::ListingResponse::ListingResponse(Ftp::Response Resp, const std::vector<char>& Data) :
|
|
||||||
Ftp::Response(Resp)
|
|
||||||
{
|
|
||||||
if (IsOk())
|
|
||||||
{
|
|
||||||
// Fill the array of strings
|
|
||||||
std::string Paths(Data.begin(), Data.end());
|
|
||||||
std::string::size_type LastPos = 0;
|
|
||||||
for (std::string::size_type Pos = Paths.find("\r\n"); Pos != std::string::npos; Pos = Paths.find("\r\n", LastPos))
|
|
||||||
{
|
|
||||||
myFilenames.push_back(Paths.substr(LastPos, Pos - LastPos));
|
|
||||||
LastPos = Pos + 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the number of filenames in the listing
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::size_t Ftp::ListingResponse::GetCount() const
|
|
||||||
{
|
|
||||||
return myFilenames.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the Index-th filename in the directory
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& Ftp::ListingResponse::GetFilename(std::size_t Index) const
|
|
||||||
{
|
|
||||||
return myFilenames[Index];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Destructor -- close the connection with the server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::~Ftp()
|
|
||||||
{
|
|
||||||
Disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Connect to the specified FTP server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::Connect(const IPAddress& Server, unsigned short Port, float Timeout)
|
|
||||||
{
|
|
||||||
// Connect to the server
|
|
||||||
if (myCommandSocket.Connect(Port, Server, Timeout) != Socket::Done)
|
|
||||||
return Response(Response::ConnectionFailed);
|
|
||||||
|
|
||||||
// Get the response to the connection
|
|
||||||
return GetResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Log in using anonymous account
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::Login()
|
|
||||||
{
|
|
||||||
return Login("anonymous", "user@sfml-dev.org");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Log in using a username and a password
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::Login(const std::string& UserName, const std::string& Password)
|
|
||||||
{
|
|
||||||
Response Resp = SendCommand("USER", UserName);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
Resp = SendCommand("PASS", Password);
|
|
||||||
|
|
||||||
return Resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Close the connection with FTP server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::Disconnect()
|
|
||||||
{
|
|
||||||
// Send the exit command
|
|
||||||
Response Resp = SendCommand("QUIT");
|
|
||||||
if (Resp.IsOk())
|
|
||||||
myCommandSocket.Close();
|
|
||||||
|
|
||||||
return Resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a null command just to prevent from being disconnected
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::KeepAlive()
|
|
||||||
{
|
|
||||||
return SendCommand("NOOP");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the current working directory
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::DirectoryResponse Ftp::GetWorkingDirectory()
|
|
||||||
{
|
|
||||||
return DirectoryResponse(SendCommand("PWD"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the contents of the given directory
|
|
||||||
/// (subdirectories and files)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& Directory)
|
|
||||||
{
|
|
||||||
// Open a data channel on default port (20) using ASCII transfer mode
|
|
||||||
std::vector<char> DirData;
|
|
||||||
DataChannel Data(*this);
|
|
||||||
Response Resp = Data.Open(Ascii);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Tell the server to send us the listing
|
|
||||||
Resp = SendCommand("NLST", Directory);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Receive the listing
|
|
||||||
Data.Receive(DirData);
|
|
||||||
|
|
||||||
// Get the response from the server
|
|
||||||
Resp = GetResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ListingResponse(Resp, DirData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Change the current working directory
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::ChangeDirectory(const std::string& Directory)
|
|
||||||
{
|
|
||||||
return SendCommand("CWD", Directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Go to the parent directory of the current one
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::ParentDirectory()
|
|
||||||
{
|
|
||||||
return SendCommand("CDUP");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Create a new directory
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::MakeDirectory(const std::string& Name)
|
|
||||||
{
|
|
||||||
return SendCommand("MKD", Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove an existing directory
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::DeleteDirectory(const std::string& Name)
|
|
||||||
{
|
|
||||||
return SendCommand("RMD", Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Rename a file
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::RenameFile(const std::string& File, const std::string& NewName)
|
|
||||||
{
|
|
||||||
Response Resp = SendCommand("RNFR", File);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
Resp = SendCommand("RNTO", NewName);
|
|
||||||
|
|
||||||
return Resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove an existing file
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::DeleteFile(const std::string& Name)
|
|
||||||
{
|
|
||||||
return SendCommand("DELE", Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Download a file from the server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode)
|
|
||||||
{
|
|
||||||
// Open a data channel using the given transfer mode
|
|
||||||
DataChannel Data(*this);
|
|
||||||
Response Resp = Data.Open(Mode);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Tell the server to start the transfer
|
|
||||||
Resp = SendCommand("RETR", DistantFile);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Receive the file data
|
|
||||||
std::vector<char> FileData;
|
|
||||||
Data.Receive(FileData);
|
|
||||||
|
|
||||||
// Get the response from the server
|
|
||||||
Resp = GetResponse();
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Extract the filename from the file path
|
|
||||||
std::string Filename = DistantFile;
|
|
||||||
std::string::size_type Pos = Filename.find_last_of("/\\");
|
|
||||||
if (Pos != std::string::npos)
|
|
||||||
Filename = Filename.substr(Pos + 1);
|
|
||||||
|
|
||||||
// Make sure the destination path ends with a slash
|
|
||||||
std::string Path = DestPath;
|
|
||||||
if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
|
|
||||||
Path += "/";
|
|
||||||
|
|
||||||
// Create the file and copy the received data into it
|
|
||||||
std::ofstream File((Path + Filename).c_str(), std::ios_base::binary);
|
|
||||||
if (!File)
|
|
||||||
return Response(Response::InvalidFile);
|
|
||||||
if (!FileData.empty())
|
|
||||||
File.write(&FileData[0], static_cast<std::streamsize>(FileData.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Upload a file to the server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode)
|
|
||||||
{
|
|
||||||
// Get the contents of the file to send
|
|
||||||
std::ifstream File(LocalFile.c_str(), std::ios_base::binary);
|
|
||||||
if (!File)
|
|
||||||
return Response(Response::InvalidFile);
|
|
||||||
File.seekg(0, std::ios::end);
|
|
||||||
std::size_t Length = File.tellg();
|
|
||||||
File.seekg(0, std::ios::beg);
|
|
||||||
std::vector<char> FileData(Length);
|
|
||||||
if (Length > 0)
|
|
||||||
File.read(&FileData[0], static_cast<std::streamsize>(Length));
|
|
||||||
|
|
||||||
// Extract the filename from the file path
|
|
||||||
std::string Filename = LocalFile;
|
|
||||||
std::string::size_type Pos = Filename.find_last_of("/\\");
|
|
||||||
if (Pos != std::string::npos)
|
|
||||||
Filename = Filename.substr(Pos + 1);
|
|
||||||
|
|
||||||
// Make sure the destination path ends with a slash
|
|
||||||
std::string Path = DestPath;
|
|
||||||
if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
|
|
||||||
Path += "/";
|
|
||||||
|
|
||||||
// Open a data channel using the given transfer mode
|
|
||||||
DataChannel Data(*this);
|
|
||||||
Response Resp = Data.Open(Mode);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Tell the server to start the transfer
|
|
||||||
Resp = SendCommand("STOR", Path + Filename);
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Send the file data
|
|
||||||
Data.Send(FileData);
|
|
||||||
|
|
||||||
// Get the response from the server
|
|
||||||
Resp = GetResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a command to the FTP server
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::SendCommand(const std::string& Command, const std::string& Parameter)
|
|
||||||
{
|
|
||||||
// Build the command string
|
|
||||||
std::string CommandStr;
|
|
||||||
if (Parameter != "")
|
|
||||||
CommandStr = Command + " " + Parameter + "\r\n";
|
|
||||||
else
|
|
||||||
CommandStr = Command + "\r\n";
|
|
||||||
|
|
||||||
// Send it to the server
|
|
||||||
if (myCommandSocket.Send(CommandStr.c_str(), CommandStr.length()) != sf::Socket::Done)
|
|
||||||
return Response(Response::ConnectionClosed);
|
|
||||||
|
|
||||||
// Get the response
|
|
||||||
return GetResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive a response from the server
|
|
||||||
/// (usually after a command has been sent)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::GetResponse()
|
|
||||||
{
|
|
||||||
// We'll use a variable to keep track of the last valid code.
|
|
||||||
// It is useful in case of multi-lines responses, because the end of such a response
|
|
||||||
// will start by the same code
|
|
||||||
unsigned int LastCode = 0;
|
|
||||||
bool IsInsideMultiline = false;
|
|
||||||
std::string Message;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
// Receive the response from the server
|
|
||||||
char Buffer[1024];
|
|
||||||
std::size_t Length;
|
|
||||||
if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done)
|
|
||||||
return Response(Response::ConnectionClosed);
|
|
||||||
|
|
||||||
// There can be several lines inside the received buffer, extract them all
|
|
||||||
std::istringstream In(std::string(Buffer, Length), std::ios_base::binary);
|
|
||||||
while (In)
|
|
||||||
{
|
|
||||||
// Try to extract the code
|
|
||||||
unsigned int Code;
|
|
||||||
if (In >> Code)
|
|
||||||
{
|
|
||||||
// Extract the separator
|
|
||||||
char Sep = 0;
|
|
||||||
In.get(Sep);
|
|
||||||
|
|
||||||
// The '-' character means a multiline response
|
|
||||||
if ((Sep == '-') && !IsInsideMultiline)
|
|
||||||
{
|
|
||||||
// Set the multiline flag
|
|
||||||
IsInsideMultiline = true;
|
|
||||||
|
|
||||||
// Keep track of the code
|
|
||||||
if (LastCode == 0)
|
|
||||||
LastCode = Code;
|
|
||||||
|
|
||||||
// Extract the line
|
|
||||||
std::getline(In, Message);
|
|
||||||
|
|
||||||
// Remove the ending '\r' (all lines are terminated by "\r\n")
|
|
||||||
Message.erase(Message.length() - 1);
|
|
||||||
Message = Sep + Message + "\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We must make sure that the code is the same, otherwise it means
|
|
||||||
// we haven't reached the end of the multiline response
|
|
||||||
if ((Sep != '-') && ((Code == LastCode) || (LastCode == 0)))
|
|
||||||
{
|
|
||||||
// Clear the multiline flag
|
|
||||||
IsInsideMultiline = false;
|
|
||||||
|
|
||||||
// Extract the line
|
|
||||||
std::string Line;
|
|
||||||
std::getline(In, Line);
|
|
||||||
|
|
||||||
// Remove the ending '\r' (all lines are terminated by "\r\n")
|
|
||||||
Line.erase(Line.length() - 1);
|
|
||||||
|
|
||||||
// Append it to the message
|
|
||||||
if (Code == LastCode)
|
|
||||||
{
|
|
||||||
std::ostringstream Out;
|
|
||||||
Out << Code << Sep << Line;
|
|
||||||
Message += Out.str();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Message = Sep + Line;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the response code and message
|
|
||||||
return Response(static_cast<Response::Status>(Code), Message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The line we just read was actually not a response,
|
|
||||||
// only a new part of the current multiline response
|
|
||||||
|
|
||||||
// Extract the line
|
|
||||||
std::string Line;
|
|
||||||
std::getline(In, Line);
|
|
||||||
|
|
||||||
if (!Line.empty())
|
|
||||||
{
|
|
||||||
// Remove the ending '\r' (all lines are terminated by "\r\n")
|
|
||||||
Line.erase(Line.length() - 1);
|
|
||||||
|
|
||||||
// Append it to the current message
|
|
||||||
std::ostringstream Out;
|
|
||||||
Out << Code << Sep << Line << "\n";
|
|
||||||
Message += Out.str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (LastCode != 0)
|
|
||||||
{
|
|
||||||
// It seems we are in the middle of a multiline response
|
|
||||||
|
|
||||||
// Clear the error bits of the stream
|
|
||||||
In.clear();
|
|
||||||
|
|
||||||
// Extract the line
|
|
||||||
std::string Line;
|
|
||||||
std::getline(In, Line);
|
|
||||||
|
|
||||||
if (!Line.empty())
|
|
||||||
{
|
|
||||||
// Remove the ending '\r' (all lines are terminated by "\r\n")
|
|
||||||
Line.erase(Line.length() - 1);
|
|
||||||
|
|
||||||
// Append it to the current message
|
|
||||||
Message += Line + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error : cannot extract the code, and we are not in a multiline response
|
|
||||||
return Response(Response::InvalidResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We never reach there
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::DataChannel::DataChannel(Ftp& Owner) :
|
|
||||||
myFtp(Owner)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Destructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::DataChannel::~DataChannel()
|
|
||||||
{
|
|
||||||
// Close the data socket
|
|
||||||
myDataSocket.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Open the data channel using the specified mode and port
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode Mode)
|
|
||||||
{
|
|
||||||
// Open a data connection in active mode (we connect to the server)
|
|
||||||
Ftp::Response Resp = myFtp.SendCommand("PASV");
|
|
||||||
if (Resp.IsOk())
|
|
||||||
{
|
|
||||||
// Extract the connection address and port from the response
|
|
||||||
std::string::size_type begin = Resp.GetMessage().find_first_of("0123456789");
|
|
||||||
if (begin != std::string::npos)
|
|
||||||
{
|
|
||||||
sf::Uint8 Data[6] = {0, 0, 0, 0, 0, 0};
|
|
||||||
std::string Str = Resp.GetMessage().substr(begin);
|
|
||||||
std::size_t Index = 0;
|
|
||||||
for (int i = 0; i < 6; ++i)
|
|
||||||
{
|
|
||||||
// Extract the current number
|
|
||||||
while (isdigit(Str[Index]))
|
|
||||||
{
|
|
||||||
Data[i] = Data[i] * 10 + (Str[Index] - '0');
|
|
||||||
Index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip separator
|
|
||||||
Index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconstruct connection port and address
|
|
||||||
unsigned short Port = Data[4] * 256 + Data[5];
|
|
||||||
sf::IPAddress Address(static_cast<sf::Uint8>(Data[0]),
|
|
||||||
static_cast<sf::Uint8>(Data[1]),
|
|
||||||
static_cast<sf::Uint8>(Data[2]),
|
|
||||||
static_cast<sf::Uint8>(Data[3]));
|
|
||||||
|
|
||||||
// Connect the data channel to the server
|
|
||||||
if (myDataSocket.Connect(Port, Address) == Socket::Done)
|
|
||||||
{
|
|
||||||
// Translate the transfer mode to the corresponding FTP parameter
|
|
||||||
std::string ModeStr;
|
|
||||||
switch (Mode)
|
|
||||||
{
|
|
||||||
case Ftp::Binary : ModeStr = "I"; break;
|
|
||||||
case Ftp::Ascii : ModeStr = "A"; break;
|
|
||||||
case Ftp::Ebcdic : ModeStr = "E"; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the transfer mode
|
|
||||||
Resp = myFtp.SendCommand("TYPE", ModeStr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Failed to connect to the server
|
|
||||||
Resp = Ftp::Response(Ftp::Response::ConnectionFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive data on the data channel until it is closed
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Ftp::DataChannel::Receive(std::vector<char>& Data)
|
|
||||||
{
|
|
||||||
// Receive data
|
|
||||||
Data.clear();
|
|
||||||
char Buffer[1024];
|
|
||||||
std::size_t Received;
|
|
||||||
while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done)
|
|
||||||
{
|
|
||||||
std::copy(Buffer, Buffer + Received, std::back_inserter(Data));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the data socket
|
|
||||||
myDataSocket.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send data on the data channel
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Ftp::DataChannel::Send(const std::vector<char>& Data)
|
|
||||||
{
|
|
||||||
// Send data
|
|
||||||
if (!Data.empty())
|
|
||||||
myDataSocket.Send(&Data[0], Data.size());
|
|
||||||
|
|
||||||
// Close the data socket
|
|
||||||
myDataSocket.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sf
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Network/Http.hpp>
|
#include <SFML/Network/Http.hpp>
|
||||||
#include <ctype.h>
|
#include <cctype>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -34,16 +34,12 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
// Convert a string to lower case
|
||||||
// Convenience function to convert a string to lower case
|
std::string toLower(std::string str)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::string ToLower(const std::string& Str)
|
|
||||||
{
|
{
|
||||||
std::string Ret = Str;
|
for (std::string::iterator i = str.begin(); i != str.end(); ++i)
|
||||||
for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
|
*i = static_cast<char>(std::tolower(*i));
|
||||||
*i = static_cast<char>(tolower(*i));
|
return str;
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,382 +47,330 @@ namespace
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
Http::Request::Request(const std::string& uri, Method method, const std::string& body)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body)
|
|
||||||
{
|
{
|
||||||
SetMethod(RequestMethod);
|
setMethod(method);
|
||||||
SetURI(URI);
|
setUri(uri);
|
||||||
SetHttpVersion(1, 0);
|
setHttpVersion(1, 0);
|
||||||
SetBody(Body);
|
setBody(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the value of a field; the field is added if it doesn't exist
|
void Http::Request::setField(const std::string& field, const std::string& value)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::Request::SetField(const std::string& Field, const std::string& Value)
|
|
||||||
{
|
{
|
||||||
myFields[ToLower(Field)] = Value;
|
m_fields[toLower(field)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the request method.
|
void Http::Request::setMethod(Http::Request::Method method)
|
||||||
/// This parameter is Get by default
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::Request::SetMethod(Http::Request::Method RequestMethod)
|
|
||||||
{
|
{
|
||||||
myMethod = RequestMethod;
|
m_method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the target URI of the request.
|
void Http::Request::setUri(const std::string& uri)
|
||||||
/// This parameter is "/" by default
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::Request::SetURI(const std::string& URI)
|
|
||||||
{
|
{
|
||||||
myURI = URI;
|
m_uri = uri;
|
||||||
|
|
||||||
// Make sure it starts with a '/'
|
// Make sure it starts with a '/'
|
||||||
if (myURI.empty() || (myURI[0] != '/'))
|
if (m_uri.empty() || (m_uri[0] != '/'))
|
||||||
myURI.insert(0, "/");
|
m_uri.insert(0, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the HTTP version of the request.
|
void Http::Request::setHttpVersion(unsigned int major, unsigned int minor)
|
||||||
/// This parameter is 1.0 by default
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor)
|
|
||||||
{
|
{
|
||||||
myMajorVersion = Major;
|
m_majorVersion = major;
|
||||||
myMinorVersion = Minor;
|
m_minorVersion = minor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the body of the request. This parameter is optional and
|
void Http::Request::setBody(const std::string& body)
|
||||||
/// makes sense only for POST requests.
|
|
||||||
/// This parameter is empty by default
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::Request::SetBody(const std::string& Body)
|
|
||||||
{
|
{
|
||||||
myBody = Body;
|
m_body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the string representation of a request header
|
std::string Http::Request::prepare() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::string Http::Request::ToString() const
|
|
||||||
{
|
{
|
||||||
std::ostringstream Out;
|
std::ostringstream out;
|
||||||
|
|
||||||
// Convert the method to its string representation
|
// Convert the method to its string representation
|
||||||
std::string RequestMethod;
|
std::string method;
|
||||||
switch (myMethod)
|
switch (m_method)
|
||||||
{
|
{
|
||||||
default :
|
default :
|
||||||
case Get : RequestMethod = "GET"; break;
|
case Get : method = "GET"; break;
|
||||||
case Post : RequestMethod = "POST"; break;
|
case Post : method = "POST"; break;
|
||||||
case Head : RequestMethod = "HEAD"; break;
|
case Head : method = "HEAD"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the first line containing the request type
|
// Write the first line containing the request type
|
||||||
Out << RequestMethod << " " << myURI << " ";
|
out << method << " " << m_uri << " ";
|
||||||
Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n";
|
out << "HTTP/" << m_majorVersion << "." << m_minorVersion << "\r\n";
|
||||||
|
|
||||||
// Write fields
|
// Write fields
|
||||||
for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i)
|
for (FieldTable::const_iterator i = m_fields.begin(); i != m_fields.end(); ++i)
|
||||||
{
|
{
|
||||||
Out << i->first << ": " << i->second << "\r\n";
|
out << i->first << ": " << i->second << "\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use an extra \r\n to separate the header from the body
|
// Use an extra \r\n to separate the header from the body
|
||||||
Out << "\r\n";
|
out << "\r\n";
|
||||||
|
|
||||||
// Add the body
|
// Add the body
|
||||||
Out << myBody;
|
out << m_body;
|
||||||
|
|
||||||
return Out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Check if the given field has been defined
|
bool Http::Request::hasField(const std::string& field) const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Http::Request::HasField(const std::string& Field) const
|
|
||||||
{
|
{
|
||||||
return myFields.find(Field) != myFields.end();
|
return m_fields.find(toLower(field)) != m_fields.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Http::Response::Response() :
|
Http::Response::Response() :
|
||||||
myStatus (ConnectionFailed),
|
m_status (ConnectionFailed),
|
||||||
myMajorVersion(0),
|
m_majorVersion(0),
|
||||||
myMinorVersion(0)
|
m_minorVersion(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the value of a field
|
const std::string& Http::Response::getField(const std::string& field) const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& Http::Response::GetField(const std::string& Field) const
|
|
||||||
{
|
{
|
||||||
FieldTable::const_iterator It = myFields.find(ToLower(Field));
|
FieldTable::const_iterator it = m_fields.find(toLower(field));
|
||||||
if (It != myFields.end())
|
if (it != m_fields.end())
|
||||||
{
|
{
|
||||||
return It->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static const std::string Empty = "";
|
static const std::string empty = "";
|
||||||
return Empty;
|
return empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the header's status code
|
Http::Response::Status Http::Response::getStatus() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Http::Response::Status Http::Response::GetStatus() const
|
|
||||||
{
|
{
|
||||||
return myStatus;
|
return m_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the major HTTP version number of the response
|
unsigned int Http::Response::getMajorHttpVersion() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned int Http::Response::GetMajorHttpVersion() const
|
|
||||||
{
|
{
|
||||||
return myMajorVersion;
|
return m_majorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the major HTTP version number of the response
|
unsigned int Http::Response::getMinorHttpVersion() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned int Http::Response::GetMinorHttpVersion() const
|
|
||||||
{
|
{
|
||||||
return myMinorVersion;
|
return m_minorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the body of the response. The body can contain :
|
const std::string& Http::Response::getBody() const
|
||||||
/// - the requested page (for GET requests)
|
|
||||||
/// - a response from the server (for POST requests)
|
|
||||||
/// - nothing (for HEAD requests)
|
|
||||||
/// - an error message (in case of an error)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const std::string& Http::Response::GetBody() const
|
|
||||||
{
|
{
|
||||||
return myBody;
|
return m_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the header from a response string
|
void Http::Response::parse(const std::string& data)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::Response::FromString(const std::string& Data)
|
|
||||||
{
|
{
|
||||||
std::istringstream In(Data);
|
std::istringstream in(data);
|
||||||
|
|
||||||
// Extract the HTTP version from the first line
|
// Extract the HTTP version from the first line
|
||||||
std::string Version;
|
std::string version;
|
||||||
if (In >> Version)
|
if (in >> version)
|
||||||
{
|
{
|
||||||
if ((Version.size() >= 8) && (Version[6] == '.') &&
|
if ((version.size() >= 8) && (version[6] == '.') &&
|
||||||
(ToLower(Version.substr(0, 5)) == "http/") &&
|
(toLower(version.substr(0, 5)) == "http/") &&
|
||||||
isdigit(Version[5]) && isdigit(Version[7]))
|
isdigit(version[5]) && isdigit(version[7]))
|
||||||
{
|
{
|
||||||
myMajorVersion = Version[5] - '0';
|
m_majorVersion = version[5] - '0';
|
||||||
myMinorVersion = Version[7] - '0';
|
m_minorVersion = version[7] - '0';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Invalid HTTP version
|
// Invalid HTTP version
|
||||||
myStatus = InvalidResponse;
|
m_status = InvalidResponse;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the status code from the first line
|
// Extract the status code from the first line
|
||||||
int StatusCode = 0;
|
int status;
|
||||||
if (In >> StatusCode)
|
if (in >> status)
|
||||||
{
|
{
|
||||||
myStatus = static_cast<Status>(StatusCode);
|
m_status = static_cast<Status>(status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Invalid status code
|
// Invalid status code
|
||||||
myStatus = InvalidResponse;
|
m_status = InvalidResponse;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the end of the first line
|
// Ignore the end of the first line
|
||||||
In.ignore(10000, '\n');
|
in.ignore(10000, '\n');
|
||||||
|
|
||||||
// Parse the other lines, which contain fields, one by one
|
// Parse the other lines, which contain fields, one by one
|
||||||
std::string Line;
|
std::string line;
|
||||||
while (std::getline(In, Line) && (Line.size() > 2))
|
while (std::getline(in, line) && (line.size() > 2))
|
||||||
{
|
{
|
||||||
std::string::size_type Pos = Line.find(": ");
|
std::string::size_type pos = line.find(": ");
|
||||||
if (Pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
// Extract the field name and its value
|
// Extract the field name and its value
|
||||||
std::string Field = Line.substr(0, Pos);
|
std::string field = line.substr(0, pos);
|
||||||
std::string Value = Line.substr(Pos + 2);
|
std::string value = line.substr(pos + 2);
|
||||||
|
|
||||||
// Remove any trailing \r
|
// Remove any trailing \r
|
||||||
if (!Value.empty() && (*Value.rbegin() == '\r'))
|
if (!value.empty() && (*value.rbegin() == '\r'))
|
||||||
Value.erase(Value.size() - 1);
|
value.erase(value.size() - 1);
|
||||||
|
|
||||||
// Add the field
|
// Add the field
|
||||||
myFields[ToLower(Field)] = Value;
|
m_fields[toLower(field)] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally extract the body
|
// Finally extract the body
|
||||||
myBody.clear();
|
m_body.clear();
|
||||||
std::copy(std::istreambuf_iterator<char>(In), std::istreambuf_iterator<char>(), std::back_inserter(myBody));
|
std::copy(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>(), std::back_inserter(m_body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Http::Http() :
|
Http::Http() :
|
||||||
myHost(),
|
m_host(),
|
||||||
myPort(0)
|
m_port(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the Http instance with the target host
|
Http::Http(const std::string& host, unsigned short port)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Http::Http(const std::string& Host, unsigned short Port)
|
|
||||||
{
|
{
|
||||||
SetHost(Host, Port);
|
setHost(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set the target host
|
void Http::setHost(const std::string& host, unsigned short port)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Http::SetHost(const std::string& Host, unsigned short Port)
|
|
||||||
{
|
{
|
||||||
// Detect the protocol used
|
// Detect the protocol used
|
||||||
std::string Protocol = ToLower(Host.substr(0, 8));
|
std::string protocol = toLower(host.substr(0, 8));
|
||||||
if (Protocol.substr(0, 7) == "http://")
|
if (protocol.substr(0, 7) == "http://")
|
||||||
{
|
{
|
||||||
// HTTP protocol
|
// HTTP protocol
|
||||||
myHostName = Host.substr(7);
|
m_hostName = host.substr(7);
|
||||||
myPort = (Port != 0 ? Port : 80);
|
m_port = (port != 0 ? port : 80);
|
||||||
}
|
}
|
||||||
else if (Protocol == "https://")
|
else if (protocol == "https://")
|
||||||
{
|
{
|
||||||
// HTTPS protocol
|
// HTTPS protocol
|
||||||
myHostName = Host.substr(8);
|
m_hostName = host.substr(8);
|
||||||
myPort = (Port != 0 ? Port : 443);
|
m_port = (port != 0 ? port : 443);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Undefined protocol - use HTTP
|
// Undefined protocol - use HTTP
|
||||||
myHostName = Host;
|
m_hostName = host;
|
||||||
myPort = (Port != 0 ? Port : 80);
|
m_port = (port != 0 ? port : 80);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any trailing '/' from the host name
|
// Remove any trailing '/' from the host name
|
||||||
if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
|
if (!m_hostName.empty() && (*m_hostName.rbegin() == '/'))
|
||||||
myHostName.erase(myHostName.size() - 1);
|
m_hostName.erase(m_hostName.size() - 1);
|
||||||
|
|
||||||
myHost = sf::IPAddress(myHostName);
|
m_host = IpAddress(m_hostName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Send a HTTP request and return the server's response.
|
Http::Response Http::sendRequest(const Http::Request& request, Time timeout)
|
||||||
/// You must be connected to a host before sending requests.
|
|
||||||
/// Any missing mandatory header field will be added with an appropriate value.
|
|
||||||
/// Warning : this function waits for the server's response and may
|
|
||||||
/// not return instantly; use a thread if you don't want to block your
|
|
||||||
/// application.
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Http::Response Http::SendRequest(const Http::Request& Req, float Timeout)
|
|
||||||
{
|
{
|
||||||
// First make sure the request is valid -- add missing mandatory fields
|
// First make sure that the request is valid -- add missing mandatory fields
|
||||||
Request ToSend(Req);
|
Request toSend(request);
|
||||||
if (!ToSend.HasField("From"))
|
if (!toSend.hasField("From"))
|
||||||
{
|
{
|
||||||
ToSend.SetField("From", "user@sfml-dev.org");
|
toSend.setField("From", "user@sfml-dev.org");
|
||||||
}
|
}
|
||||||
if (!ToSend.HasField("User-Agent"))
|
if (!toSend.hasField("User-Agent"))
|
||||||
{
|
{
|
||||||
ToSend.SetField("User-Agent", "libsfml-network/1.x");
|
toSend.setField("User-Agent", "libsfml-network/2.x");
|
||||||
}
|
}
|
||||||
if (!ToSend.HasField("Host"))
|
if (!toSend.hasField("Host"))
|
||||||
{
|
{
|
||||||
ToSend.SetField("Host", myHostName);
|
toSend.setField("Host", m_hostName);
|
||||||
}
|
}
|
||||||
if (!ToSend.HasField("Content-Length"))
|
if (!toSend.hasField("Content-Length"))
|
||||||
{
|
{
|
||||||
std::ostringstream Out;
|
std::ostringstream out;
|
||||||
Out << ToSend.myBody.size();
|
out << toSend.m_body.size();
|
||||||
ToSend.SetField("Content-Length", Out.str());
|
toSend.setField("Content-Length", out.str());
|
||||||
}
|
}
|
||||||
if ((ToSend.myMethod == Request::Post) && !ToSend.HasField("Content-Type"))
|
if ((toSend.m_method == Request::Post) && !toSend.hasField("Content-Type"))
|
||||||
{
|
{
|
||||||
ToSend.SetField("Content-Type", "application/x-www-form-urlencoded");
|
toSend.setField("Content-Type", "application/x-www-form-urlencoded");
|
||||||
}
|
}
|
||||||
if ((ToSend.myMajorVersion * 10 + ToSend.myMinorVersion >= 11) && !ToSend.HasField("Connection"))
|
if ((toSend.m_majorVersion * 10 + toSend.m_minorVersion >= 11) && !toSend.hasField("Connection"))
|
||||||
{
|
{
|
||||||
ToSend.SetField("Connection", "close");
|
toSend.setField("Connection", "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the response
|
// Prepare the response
|
||||||
Response Received;
|
Response received;
|
||||||
|
|
||||||
// Connect the socket to the host
|
// Connect the socket to the host
|
||||||
if (myConnection.Connect(myPort, myHost, Timeout) == Socket::Done)
|
if (m_connection.connect(m_host, m_port, timeout) == Socket::Done)
|
||||||
{
|
{
|
||||||
// Convert the request to string and send it through the connected socket
|
// Convert the request to string and send it through the connected socket
|
||||||
std::string RequestStr = ToSend.ToString();
|
std::string requestStr = toSend.prepare();
|
||||||
|
|
||||||
if (!RequestStr.empty())
|
if (!requestStr.empty())
|
||||||
{
|
{
|
||||||
// Send it through the socket
|
// Send it through the socket
|
||||||
if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
|
if (m_connection.send(requestStr.c_str(), requestStr.size()) == Socket::Done)
|
||||||
{
|
{
|
||||||
// Wait for the server's response
|
// Wait for the server's response
|
||||||
std::string ReceivedStr;
|
std::string receivedStr;
|
||||||
std::size_t Size = 0;
|
std::size_t size = 0;
|
||||||
char Buffer[1024];
|
char buffer[1024];
|
||||||
while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
|
while (m_connection.receive(buffer, sizeof(buffer), size) == Socket::Done)
|
||||||
{
|
{
|
||||||
ReceivedStr.append(Buffer, Buffer + Size);
|
receivedStr.append(buffer, buffer + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the Response object from the received data
|
// Build the Response object from the received data
|
||||||
Received.FromString(ReceivedStr);
|
received.parse(receivedStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the connection
|
// Close the connection
|
||||||
myConnection.Close();
|
m_connection.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Received;
|
return received;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -27,272 +27,229 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Network/IPAddress.hpp>
|
#include <SFML/Network/IPAddress.hpp>
|
||||||
#include <SFML/Network/Http.hpp>
|
#include <SFML/Network/Http.hpp>
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
sf::Uint32 resolve(const std::string& address)
|
||||||
|
{
|
||||||
|
if (address == "255.255.255.255")
|
||||||
|
{
|
||||||
|
// The broadcast address needs to be handled explicitely,
|
||||||
|
// because it is also the value returned by inet_addr on error
|
||||||
|
return INADDR_BROADCAST;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx")
|
||||||
|
sf::Uint32 ip = inet_addr(address.c_str());
|
||||||
|
if (ip != INADDR_NONE)
|
||||||
|
return ip;
|
||||||
|
|
||||||
|
// Not a valid address, try to convert it as a host name
|
||||||
|
addrinfo hints;
|
||||||
|
std::memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
addrinfo* result = NULL;
|
||||||
|
if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0)
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
ip = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr;
|
||||||
|
freeaddrinfo(result);
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a valid address nor a host name
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Static member data
|
const IpAddress IpAddress::None;
|
||||||
////////////////////////////////////////////////////////////
|
const IpAddress IpAddress::LocalHost(127, 0, 0, 1);
|
||||||
const IPAddress IPAddress::LocalHost("127.0.0.1");
|
const IpAddress IpAddress::Broadcast(255, 255, 255, 255);
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
IpAddress::IpAddress() :
|
||||||
////////////////////////////////////////////////////////////
|
m_address(0)
|
||||||
IPAddress::IPAddress() :
|
|
||||||
myAddress(INADDR_NONE)
|
|
||||||
{
|
{
|
||||||
|
// We're using 0 (INADDR_ANY) instead of INADDR_NONE to represent the invalid address,
|
||||||
|
// because the latter is also the broadcast address (255.255.255.255); it's ok because
|
||||||
|
// SFML doesn't publicly use INADDR_ANY (it is always used implicitely)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from a string
|
IpAddress::IpAddress(const std::string& address) :
|
||||||
////////////////////////////////////////////////////////////
|
m_address(resolve(address))
|
||||||
IPAddress::IPAddress(const std::string& Address)
|
|
||||||
{
|
{
|
||||||
// First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
|
|
||||||
myAddress = inet_addr(Address.c_str());
|
|
||||||
|
|
||||||
// If not successful, try to convert it as a host name
|
|
||||||
if (!IsValid())
|
|
||||||
{
|
|
||||||
hostent* Host = gethostbyname(Address.c_str());
|
|
||||||
if (Host)
|
|
||||||
{
|
|
||||||
// Host found, extract its IP address
|
|
||||||
myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Host name not found on the network
|
|
||||||
myAddress = INADDR_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from a C-style string ;
|
IpAddress::IpAddress(const char* address) :
|
||||||
/// Needed for implicit conversions from literal strings to IPAddress to work
|
m_address(resolve(address))
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
IPAddress::IPAddress(const char* Address)
|
|
||||||
{
|
{
|
||||||
// First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
|
|
||||||
myAddress = inet_addr(Address);
|
|
||||||
|
|
||||||
// If not successful, try to convert it as a host name
|
|
||||||
if (!IsValid())
|
|
||||||
{
|
|
||||||
hostent* Host = gethostbyname(Address);
|
|
||||||
if (Host)
|
|
||||||
{
|
|
||||||
// Host found, extract its IP address
|
|
||||||
myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Host name not found on the network
|
|
||||||
myAddress = INADDR_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from 4 bytes
|
IpAddress::IpAddress(Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3) :
|
||||||
////////////////////////////////////////////////////////////
|
m_address(htonl((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3))
|
||||||
IPAddress::IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3)
|
|
||||||
{
|
{
|
||||||
myAddress = htonl((Byte0 << 24) | (Byte1 << 16) | (Byte2 << 8) | Byte3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Construct the address from a 32-bits integer
|
IpAddress::IpAddress(Uint32 address) :
|
||||||
////////////////////////////////////////////////////////////
|
m_address(htonl(address))
|
||||||
IPAddress::IPAddress(Uint32 Address)
|
|
||||||
{
|
{
|
||||||
myAddress = htonl(Address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Tell if the address is a valid one
|
std::string IpAddress::toString() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::IsValid() const
|
|
||||||
{
|
{
|
||||||
return myAddress != INADDR_NONE;
|
in_addr address;
|
||||||
|
address.s_addr = m_address;
|
||||||
|
|
||||||
|
return inet_ntoa(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get a string representation of the address
|
Uint32 IpAddress::toInteger() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::string IPAddress::ToString() const
|
|
||||||
{
|
{
|
||||||
in_addr InAddr;
|
return ntohl(m_address);
|
||||||
InAddr.s_addr = myAddress;
|
|
||||||
|
|
||||||
return inet_ntoa(InAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get an integer representation of the address
|
IpAddress IpAddress::getLocalAddress()
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Uint32 IPAddress::ToInteger() const
|
|
||||||
{
|
|
||||||
return ntohl(myAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the computer's local IP address (from the LAN point of view)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
IPAddress IPAddress::GetLocalAddress()
|
|
||||||
{
|
{
|
||||||
// The method here is to connect a UDP socket to anyone (here to localhost),
|
// The method here is to connect a UDP socket to anyone (here to localhost),
|
||||||
// and get the local socket address with the getsockname function.
|
// and get the local socket address with the getsockname function.
|
||||||
// UDP connection will not send anything to the network, so this function won't cause any overhead.
|
// UDP connection will not send anything to the network, so this function won't cause any overhead.
|
||||||
|
|
||||||
IPAddress LocalAddress;
|
IpAddress localAddress;
|
||||||
|
|
||||||
// Create the socket
|
// Create the socket
|
||||||
SocketHelper::SocketType Socket = socket(PF_INET, SOCK_DGRAM, 0);
|
SocketHandle sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
if (Socket == SocketHelper::InvalidSocket())
|
if (sock == priv::SocketImpl::invalidSocket())
|
||||||
return LocalAddress;
|
return localAddress;
|
||||||
|
|
||||||
// Build the host address (use a random port)
|
// Connect the socket to localhost on any port
|
||||||
sockaddr_in SockAddr;
|
sockaddr_in address = priv::SocketImpl::createAddress(ntohl(INADDR_LOOPBACK), 0);
|
||||||
memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
|
if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||||
SockAddr.sin_addr.s_addr = INADDR_LOOPBACK;
|
|
||||||
SockAddr.sin_family = AF_INET;
|
|
||||||
SockAddr.sin_port = htons(4567);
|
|
||||||
|
|
||||||
// Connect the socket
|
|
||||||
if (connect(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
|
|
||||||
{
|
{
|
||||||
SocketHelper::Close(Socket);
|
priv::SocketImpl::close(sock);
|
||||||
return LocalAddress;
|
return localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the local address of the socket connection
|
// Get the local address of the socket connection
|
||||||
SocketHelper::LengthType Size = sizeof(SockAddr);
|
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||||
if (getsockname(Socket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) == -1)
|
if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1)
|
||||||
{
|
{
|
||||||
SocketHelper::Close(Socket);
|
priv::SocketImpl::close(sock);
|
||||||
return LocalAddress;
|
return localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the socket
|
// Close the socket
|
||||||
SocketHelper::Close(Socket);
|
priv::SocketImpl::close(sock);
|
||||||
|
|
||||||
// Finally build the IP address
|
// Finally build the IP address
|
||||||
LocalAddress.myAddress = SockAddr.sin_addr.s_addr;
|
localAddress = IpAddress(ntohl(address.sin_addr.s_addr));
|
||||||
|
|
||||||
return LocalAddress;
|
return localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the computer's public IP address (from the web point of view)
|
IpAddress IpAddress::getPublicAddress(Time timeout)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
IPAddress IPAddress::GetPublicAddress(float Timeout)
|
|
||||||
{
|
{
|
||||||
// The trick here is more complicated, because the only way
|
// The trick here is more complicated, because the only way
|
||||||
// to get our public IP address is to get it from a distant computer.
|
// to get our public IP address is to get it from a distant computer.
|
||||||
// Here we get the web page from http://www.sfml-dev.org/ip-provider.php
|
// Here we get the web page from http://www.sfml-dev.org/ip-provider.php
|
||||||
// and parse the result to extract our IP address
|
// and parse the result to extract our IP address
|
||||||
// (not very hard : the web page contains only our IP address).
|
// (not very hard: the web page contains only our IP address).
|
||||||
|
|
||||||
Http Server("www.sfml-dev.org");
|
Http server("www.sfml-dev.org");
|
||||||
Http::Request Request(Http::Request::Get, "/ip-provider.php");
|
Http::Request request("/ip-provider.php", Http::Request::Get);
|
||||||
Http::Response Page = Server.SendRequest(Request, Timeout);
|
Http::Response page = server.sendRequest(request, timeout);
|
||||||
if (Page.GetStatus() == Http::Response::Ok)
|
if (page.getStatus() == Http::Response::Ok)
|
||||||
return IPAddress(Page.GetBody());
|
return IpAddress(page.getBody());
|
||||||
|
|
||||||
// Something failed: return an invalid address
|
// Something failed: return an invalid address
|
||||||
return IPAddress();
|
return IpAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Comparison operator ==
|
bool operator ==(const IpAddress& left, const IpAddress& right)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::operator ==(const IPAddress& Other) const
|
|
||||||
{
|
{
|
||||||
return myAddress == Other.myAddress;
|
return left.toInteger() == right.toInteger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Comparison operator !=
|
bool operator !=(const IpAddress& left, const IpAddress& right)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::operator !=(const IPAddress& Other) const
|
|
||||||
{
|
{
|
||||||
return myAddress != Other.myAddress;
|
return !(left == right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Comparison operator <
|
bool operator <(const IpAddress& left, const IpAddress& right)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::operator <(const IPAddress& Other) const
|
|
||||||
{
|
{
|
||||||
return myAddress < Other.myAddress;
|
return left.toInteger() < right.toInteger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Comparison operator >
|
bool operator >(const IpAddress& left, const IpAddress& right)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::operator >(const IPAddress& Other) const
|
|
||||||
{
|
{
|
||||||
return myAddress > Other.myAddress;
|
return right < left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Comparison operator <=
|
bool operator <=(const IpAddress& left, const IpAddress& right)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::operator <=(const IPAddress& Other) const
|
|
||||||
{
|
{
|
||||||
return myAddress <= Other.myAddress;
|
return !(right < left);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Comparison operator >=
|
bool operator >=(const IpAddress& left, const IpAddress& right)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool IPAddress::operator >=(const IPAddress& Other) const
|
|
||||||
{
|
{
|
||||||
return myAddress >= Other.myAddress;
|
return !(left < right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator >> overload to extract an address from an input stream
|
std::istream& operator >>(std::istream& stream, IpAddress& address)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::istream& operator >>(std::istream& Stream, IPAddress& Address)
|
|
||||||
{
|
{
|
||||||
std::string Str;
|
std::string str;
|
||||||
Stream >> Str;
|
stream >> str;
|
||||||
Address = IPAddress(Str);
|
address = IpAddress(str);
|
||||||
|
|
||||||
return Stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator << overload to print an address to an output stream
|
std::ostream& operator <<(std::ostream& stream, const IpAddress& address)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address)
|
|
||||||
{
|
{
|
||||||
return Stream << Address.ToString();
|
return stream << address.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -26,25 +26,23 @@
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Network/Packet.hpp>
|
#include <SFML/Network/Packet.hpp>
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
#include <string.h>
|
#include <SFML/System/String.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cwchar>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Packet::Packet() :
|
Packet::Packet() :
|
||||||
myReadPos(0),
|
m_readPos(0),
|
||||||
myIsValid(true)
|
m_isValid(true)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Virtual destructor
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Packet::~Packet()
|
Packet::~Packet()
|
||||||
{
|
{
|
||||||
|
@ -53,230 +51,250 @@ Packet::~Packet()
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Append data to the end of the packet
|
void Packet::append(const void* data, std::size_t sizeInBytes)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Packet::Append(const void* Data, std::size_t SizeInBytes)
|
|
||||||
{
|
{
|
||||||
if (Data && (SizeInBytes > 0))
|
if (data && (sizeInBytes > 0))
|
||||||
{
|
{
|
||||||
std::size_t Start = myData.size();
|
std::size_t start = m_data.size();
|
||||||
myData.resize(Start + SizeInBytes);
|
m_data.resize(start + sizeInBytes);
|
||||||
memcpy(&myData[Start], Data, SizeInBytes);
|
std::memcpy(&m_data[start], data, sizeInBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Clear the packet data
|
void Packet::clear()
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Packet::Clear()
|
|
||||||
{
|
{
|
||||||
myData.clear();
|
m_data.clear();
|
||||||
myReadPos = 0;
|
m_readPos = 0;
|
||||||
myIsValid = true;
|
m_isValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get a pointer to the data contained in the packet
|
const void* Packet::getData() const
|
||||||
/// Warning : the returned pointer may be invalid after you
|
|
||||||
/// append data to the packet
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const char* Packet::GetData() const
|
|
||||||
{
|
{
|
||||||
return !myData.empty() ? &myData[0] : NULL;
|
return !m_data.empty() ? &m_data[0] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the size of the data contained in the packet
|
std::size_t Packet::getDataSize() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
std::size_t Packet::GetDataSize() const
|
|
||||||
{
|
{
|
||||||
return myData.size();
|
return m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Tell if the reading position has reached the end of the packet
|
bool Packet::endOfPacket() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Packet::EndOfPacket() const
|
|
||||||
{
|
{
|
||||||
return myReadPos >= myData.size();
|
return m_readPos >= m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Tell if the packet is valid for reading
|
Packet::operator BoolType() const
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Packet::operator bool() const
|
|
||||||
{
|
{
|
||||||
return myIsValid;
|
return m_isValid ? &Packet::checkSize : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator >> overloads to extract data from the packet
|
Packet& Packet::operator >>(bool& data)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Packet& Packet::operator >>(bool& Data)
|
|
||||||
{
|
{
|
||||||
Uint8 Value;
|
Uint8 value;
|
||||||
if (*this >> Value)
|
if (*this >> value)
|
||||||
Data = (Value != 0);
|
data = (value != 0);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(Int8& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(Int8& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = *reinterpret_cast<const Int8*>(GetData() + myReadPos);
|
data = *reinterpret_cast<const Int8*>(&m_data[m_readPos]);
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(Uint8& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(Uint8& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = *reinterpret_cast<const Uint8*>(GetData() + myReadPos);
|
data = *reinterpret_cast<const Uint8*>(&m_data[m_readPos]);
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(Int16& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(Int16& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = ntohs(*reinterpret_cast<const Int16*>(GetData() + myReadPos));
|
data = ntohs(*reinterpret_cast<const Int16*>(&m_data[m_readPos]));
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(Uint16& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(Uint16& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = ntohs(*reinterpret_cast<const Uint16*>(GetData() + myReadPos));
|
data = ntohs(*reinterpret_cast<const Uint16*>(&m_data[m_readPos]));
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(Int32& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(Int32& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = ntohl(*reinterpret_cast<const Int32*>(GetData() + myReadPos));
|
data = ntohl(*reinterpret_cast<const Int32*>(&m_data[m_readPos]));
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(Uint32& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(Uint32& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = ntohl(*reinterpret_cast<const Uint32*>(GetData() + myReadPos));
|
data = ntohl(*reinterpret_cast<const Uint32*>(&m_data[m_readPos]));
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(float& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(float& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = *reinterpret_cast<const float*>(GetData() + myReadPos);
|
data = *reinterpret_cast<const float*>(&m_data[m_readPos]);
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(double& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(double& data)
|
||||||
{
|
{
|
||||||
if (CheckSize(sizeof(Data)))
|
if (checkSize(sizeof(data)))
|
||||||
{
|
{
|
||||||
Data = *reinterpret_cast<const double*>(GetData() + myReadPos);
|
data = *reinterpret_cast<const double*>(&m_data[m_readPos]);
|
||||||
myReadPos += sizeof(Data);
|
m_readPos += sizeof(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(char* Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(char* data)
|
||||||
{
|
{
|
||||||
// First extract string length
|
// First extract string length
|
||||||
Uint32 Length = 0;
|
Uint32 length = 0;
|
||||||
*this >> Length;
|
*this >> length;
|
||||||
|
|
||||||
if ((Length > 0) && CheckSize(Length))
|
if ((length > 0) && checkSize(length))
|
||||||
{
|
{
|
||||||
// Then extract characters
|
// Then extract characters
|
||||||
memcpy(Data, GetData() + myReadPos, Length);
|
std::memcpy(data, &m_data[m_readPos], length);
|
||||||
Data[Length] = '\0';
|
data[length] = '\0';
|
||||||
|
|
||||||
// Update reading position
|
// Update reading position
|
||||||
myReadPos += Length;
|
m_readPos += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(std::string& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(std::string& data)
|
||||||
{
|
{
|
||||||
// First extract string length
|
// First extract string length
|
||||||
Uint32 Length = 0;
|
Uint32 length = 0;
|
||||||
*this >> Length;
|
*this >> length;
|
||||||
|
|
||||||
Data.clear();
|
data.clear();
|
||||||
if ((Length > 0) && CheckSize(Length))
|
if ((length > 0) && checkSize(length))
|
||||||
{
|
{
|
||||||
// Then extract characters
|
// Then extract characters
|
||||||
Data.assign(GetData() + myReadPos, Length);
|
data.assign(&m_data[m_readPos], length);
|
||||||
|
|
||||||
// Update reading position
|
// Update reading position
|
||||||
myReadPos += Length;
|
m_readPos += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(wchar_t* Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(wchar_t* data)
|
||||||
{
|
{
|
||||||
// First extract string length
|
// First extract string length
|
||||||
Uint32 Length = 0;
|
Uint32 length = 0;
|
||||||
*this >> Length;
|
*this >> length;
|
||||||
|
|
||||||
if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
|
if ((length > 0) && checkSize(length * sizeof(Uint32)))
|
||||||
{
|
{
|
||||||
// Then extract characters
|
// Then extract characters
|
||||||
for (Uint32 i = 0; i < Length; ++i)
|
for (Uint32 i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
Uint32 c = 0;
|
Uint32 character = 0;
|
||||||
*this >> c;
|
*this >> character;
|
||||||
Data[i] = static_cast<wchar_t>(c);
|
data[i] = static_cast<wchar_t>(character);
|
||||||
}
|
}
|
||||||
Data[Length] = L'\0';
|
data[length] = L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Packet& Packet::operator >>(std::wstring& Data)
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator >>(std::wstring& data)
|
||||||
{
|
{
|
||||||
// First extract string length
|
// First extract string length
|
||||||
Uint32 Length = 0;
|
Uint32 length = 0;
|
||||||
*this >> Length;
|
*this >> length;
|
||||||
|
|
||||||
Data.clear();
|
data.clear();
|
||||||
if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
|
if ((length > 0) && checkSize(length * sizeof(Uint32)))
|
||||||
{
|
{
|
||||||
// Then extract characters
|
// Then extract characters
|
||||||
for (Uint32 i = 0; i < Length; ++i)
|
for (Uint32 i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
Uint32 c = 0;
|
Uint32 character = 0;
|
||||||
*this >> c;
|
*this >> character;
|
||||||
Data += static_cast<wchar_t>(c);
|
data += static_cast<wchar_t>(character);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,109 +303,22 @@ Packet& Packet::operator >>(std::wstring& Data)
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Operator << overloads to put data into the packet
|
Packet& Packet::operator >>(String& data)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Packet& Packet::operator <<(bool Data)
|
|
||||||
{
|
{
|
||||||
*this << static_cast<Uint8>(Data);
|
// First extract the string length
|
||||||
return *this;
|
Uint32 length = 0;
|
||||||
}
|
*this >> length;
|
||||||
Packet& Packet::operator <<(Int8 Data)
|
|
||||||
{
|
|
||||||
Append(&Data, sizeof(Data));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(Uint8 Data)
|
|
||||||
{
|
|
||||||
Append(&Data, sizeof(Data));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(Int16 Data)
|
|
||||||
{
|
|
||||||
Int16 ToWrite = htons(Data);
|
|
||||||
Append(&ToWrite, sizeof(ToWrite));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(Uint16 Data)
|
|
||||||
{
|
|
||||||
Uint16 ToWrite = htons(Data);
|
|
||||||
Append(&ToWrite, sizeof(ToWrite));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(Int32 Data)
|
|
||||||
{
|
|
||||||
Int32 ToWrite = htonl(Data);
|
|
||||||
Append(&ToWrite, sizeof(ToWrite));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(Uint32 Data)
|
|
||||||
{
|
|
||||||
Uint32 ToWrite = htonl(Data);
|
|
||||||
Append(&ToWrite, sizeof(ToWrite));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(float Data)
|
|
||||||
{
|
|
||||||
Append(&Data, sizeof(Data));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(double Data)
|
|
||||||
{
|
|
||||||
Append(&Data, sizeof(Data));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(const char* Data)
|
|
||||||
{
|
|
||||||
// First insert string length
|
|
||||||
Uint32 Length = 0;
|
|
||||||
for (const char* c = Data; *c != '\0'; ++c)
|
|
||||||
++Length;
|
|
||||||
*this << Length;
|
|
||||||
|
|
||||||
// Then insert characters
|
data.clear();
|
||||||
Append(Data, Length * sizeof(char));
|
if ((length > 0) && checkSize(length * sizeof(Uint32)))
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(const std::string& Data)
|
|
||||||
{
|
|
||||||
// First insert string length
|
|
||||||
Uint32 Length = static_cast<Uint32>(Data.size());
|
|
||||||
*this << Length;
|
|
||||||
|
|
||||||
// Then insert characters
|
|
||||||
if (Length > 0)
|
|
||||||
{
|
{
|
||||||
Append(Data.c_str(), Length * sizeof(std::string::value_type));
|
// Then extract characters
|
||||||
}
|
for (Uint32 i = 0; i < length; ++i)
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(const wchar_t* Data)
|
|
||||||
{
|
|
||||||
// First insert string length
|
|
||||||
Uint32 Length = 0;
|
|
||||||
for (const wchar_t* c = Data; *c != L'\0'; ++c)
|
|
||||||
++Length;
|
|
||||||
*this << Length;
|
|
||||||
|
|
||||||
// Then insert characters
|
|
||||||
for (const wchar_t* c = Data; *c != L'\0'; ++c)
|
|
||||||
*this << static_cast<Int32>(*c);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
Packet& Packet::operator <<(const std::wstring& Data)
|
|
||||||
{
|
|
||||||
// First insert string length
|
|
||||||
Uint32 Length = static_cast<Uint32>(Data.size());
|
|
||||||
*this << Length;
|
|
||||||
|
|
||||||
// Then insert characters
|
|
||||||
if (Length > 0)
|
|
||||||
{
|
{
|
||||||
for (std::wstring::const_iterator c = Data.begin(); c != Data.end(); ++c)
|
Uint32 character = 0;
|
||||||
*this << static_cast<Int32>(*c);
|
*this >> character;
|
||||||
|
data += character;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -395,32 +326,182 @@ Packet& Packet::operator <<(const std::wstring& Data)
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Check if the packet can extract a given size of bytes
|
Packet& Packet::operator <<(bool data)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool Packet::CheckSize(std::size_t Size)
|
|
||||||
{
|
{
|
||||||
myIsValid = myIsValid && (myReadPos + Size <= myData.size());
|
*this << static_cast<Uint8>(data);
|
||||||
|
return *this;
|
||||||
return myIsValid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Called before the packet is sent to the network
|
Packet& Packet::operator <<(Int8 data)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
const char* Packet::OnSend(std::size_t& DataSize)
|
|
||||||
{
|
{
|
||||||
DataSize = GetDataSize();
|
append(&data, sizeof(data));
|
||||||
return GetData();
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Called after the packet has been received from the network
|
Packet& Packet::operator <<(Uint8 data)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void Packet::OnReceive(const char* Data, std::size_t DataSize)
|
|
||||||
{
|
{
|
||||||
Append(Data, DataSize);
|
append(&data, sizeof(data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(Int16 data)
|
||||||
|
{
|
||||||
|
Int16 toWrite = htons(data);
|
||||||
|
append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(Uint16 data)
|
||||||
|
{
|
||||||
|
Uint16 toWrite = htons(data);
|
||||||
|
append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(Int32 data)
|
||||||
|
{
|
||||||
|
Int32 toWrite = htonl(data);
|
||||||
|
append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(Uint32 data)
|
||||||
|
{
|
||||||
|
Uint32 toWrite = htonl(data);
|
||||||
|
append(&toWrite, sizeof(toWrite));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(float data)
|
||||||
|
{
|
||||||
|
append(&data, sizeof(data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(double data)
|
||||||
|
{
|
||||||
|
append(&data, sizeof(data));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(const char* data)
|
||||||
|
{
|
||||||
|
// First insert string length
|
||||||
|
Uint32 length = std::strlen(data);
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
append(data, length * sizeof(char));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(const std::string& data)
|
||||||
|
{
|
||||||
|
// First insert string length
|
||||||
|
Uint32 length = static_cast<Uint32>(data.size());
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
if (length > 0)
|
||||||
|
append(data.c_str(), length * sizeof(std::string::value_type));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(const wchar_t* data)
|
||||||
|
{
|
||||||
|
// First insert string length
|
||||||
|
Uint32 length = std::wcslen(data);
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
for (const wchar_t* c = data; *c != L'\0'; ++c)
|
||||||
|
*this << static_cast<Uint32>(*c);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(const std::wstring& data)
|
||||||
|
{
|
||||||
|
// First insert string length
|
||||||
|
Uint32 length = static_cast<Uint32>(data.size());
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
for (std::wstring::const_iterator c = data.begin(); c != data.end(); ++c)
|
||||||
|
*this << static_cast<Uint32>(*c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& Packet::operator <<(const String& data)
|
||||||
|
{
|
||||||
|
// First insert the string length
|
||||||
|
Uint32 length = static_cast<Uint32>(data.getSize());
|
||||||
|
*this << length;
|
||||||
|
|
||||||
|
// Then insert characters
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
for (String::ConstIterator c = data.begin(); c != data.end(); ++c)
|
||||||
|
*this << *c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool Packet::checkSize(std::size_t size)
|
||||||
|
{
|
||||||
|
m_isValid = m_isValid && (m_readPos + size <= m_data.size());
|
||||||
|
|
||||||
|
return m_isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
const void* Packet::onSend(std::size_t& size)
|
||||||
|
{
|
||||||
|
size = getDataSize();
|
||||||
|
return getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void Packet::onReceive(const void* data, std::size_t size)
|
||||||
|
{
|
||||||
|
append(data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/SelectorBase.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SelectorBase::SelectorBase() :
|
|
||||||
myMaxSocket(0)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Add a socket to watch
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SelectorBase::Add(SocketHelper::SocketType Socket)
|
|
||||||
{
|
|
||||||
FD_SET(Socket, &mySet);
|
|
||||||
|
|
||||||
int Size = static_cast<int>(Socket);
|
|
||||||
if (Size > myMaxSocket)
|
|
||||||
myMaxSocket = Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove a socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SelectorBase::Remove(SocketHelper::SocketType Socket)
|
|
||||||
{
|
|
||||||
FD_CLR(Socket, &mySet);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Remove all sockets
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SelectorBase::Clear()
|
|
||||||
{
|
|
||||||
FD_ZERO(&mySet);
|
|
||||||
FD_ZERO(&mySetReady);
|
|
||||||
|
|
||||||
myMaxSocket = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Wait and collect sockets which are ready for reading.
|
|
||||||
/// This functions will return either when at least one socket
|
|
||||||
/// is ready, or when the given time is out
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned int SelectorBase::Wait(float Timeout)
|
|
||||||
{
|
|
||||||
// Setup the timeout structure
|
|
||||||
timeval Time;
|
|
||||||
Time.tv_sec = static_cast<long>(Timeout);
|
|
||||||
Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
|
|
||||||
|
|
||||||
// Prepare the set of sockets to return
|
|
||||||
mySetReady = mySet;
|
|
||||||
|
|
||||||
// Wait until one of the sockets is ready for reading, or timeout is reached
|
|
||||||
int NbSockets = select(myMaxSocket + 1, &mySetReady, NULL, NULL, Timeout > 0 ? &Time : NULL);
|
|
||||||
|
|
||||||
return NbSockets >= 0 ? static_cast<unsigned int>(NbSockets) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// After a call to Wait(), get the Index-th socket which is
|
|
||||||
/// ready for reading. The total number of sockets ready
|
|
||||||
/// is the integer returned by the previous call to Wait()
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketHelper::SocketType SelectorBase::GetSocketReady(unsigned int Index)
|
|
||||||
{
|
|
||||||
// The standard FD_xxx interface doesn't define a direct access,
|
|
||||||
// so we must go through the whole set to find the socket we're looking for
|
|
||||||
for (int i = 0; i < myMaxSocket + 1; ++i)
|
|
||||||
{
|
|
||||||
if (FD_ISSET(i, &mySetReady))
|
|
||||||
{
|
|
||||||
// Current socket is ready, but is it the Index-th one ?
|
|
||||||
if (Index > 0)
|
|
||||||
{
|
|
||||||
Index--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return static_cast<SocketHelper::SocketType>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalid index : return an invalid socket
|
|
||||||
return SocketHelper::InvalidSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sf
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Socket(Type type) :
|
||||||
|
m_type (type),
|
||||||
|
m_socket (priv::SocketImpl::invalidSocket()),
|
||||||
|
m_isBlocking(true)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::~Socket()
|
||||||
|
{
|
||||||
|
// Close the socket before it gets destructed
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void Socket::setBlocking(bool blocking)
|
||||||
|
{
|
||||||
|
// Apply if the socket is already created
|
||||||
|
if (m_socket != priv::SocketImpl::invalidSocket())
|
||||||
|
priv::SocketImpl::setBlocking(m_socket, blocking);
|
||||||
|
|
||||||
|
m_isBlocking = blocking;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool Socket::isBlocking() const
|
||||||
|
{
|
||||||
|
return m_isBlocking;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketHandle Socket::getHandle() const
|
||||||
|
{
|
||||||
|
return m_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void Socket::create()
|
||||||
|
{
|
||||||
|
// Don't create the socket if it already exists
|
||||||
|
if (m_socket == priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
SocketHandle handle = socket(PF_INET, m_type == Tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||||
|
create(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void Socket::create(SocketHandle handle)
|
||||||
|
{
|
||||||
|
// Don't create the socket if it already exists
|
||||||
|
if (m_socket == priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
// Assign the new handle
|
||||||
|
m_socket = handle;
|
||||||
|
|
||||||
|
// Set the current blocking state
|
||||||
|
setBlocking(m_isBlocking);
|
||||||
|
|
||||||
|
if (m_type == Tcp)
|
||||||
|
{
|
||||||
|
// Disable the Nagle algorithm (ie. removes buffering of TCP packets)
|
||||||
|
int yes = 1;
|
||||||
|
if (setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||||
|
{
|
||||||
|
err() << "Failed to set socket option \"TCP_NODELAY\" ; "
|
||||||
|
<< "all your TCP packets will be buffered" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Mac OS X, disable the SIGPIPE signal on disconnection
|
||||||
|
#ifdef SFML_SYSTEM_MACOS
|
||||||
|
if (setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||||
|
{
|
||||||
|
err() << "Failed to set socket option \"SO_NOSIGPIPE\"" << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Enable broadcast by default for UDP sockets
|
||||||
|
int yes = 1;
|
||||||
|
if (setsockopt(m_socket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||||
|
{
|
||||||
|
err() << "Failed to enable broadcast on UDP socket" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void Socket::close()
|
||||||
|
{
|
||||||
|
// Close the socket
|
||||||
|
if (m_socket != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
priv::SocketImpl::close(m_socket);
|
||||||
|
m_socket = priv::SocketImpl::invalidSocket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -22,24 +22,18 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef SFML_SOCKETS_HPP
|
|
||||||
#define SFML_SOCKETS_HPP
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Config.hpp>
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
#ifdef SFML_SYSTEM_WINDOWS
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
|
||||||
#include <SFML/Network/Win32/Sockets.hpp>
|
#include <SFML/Network/Win32/SocketImpl.hpp>
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <SFML/Network/Unix/Sockets.hpp>
|
#include <SFML/Network/Unix/SocketImpl.hpp>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SOCKETS_HPP
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/SocketSelector.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct SocketSelector::SocketSelectorImpl
|
||||||
|
{
|
||||||
|
fd_set AllSockets; ///< Set containing all the sockets handles
|
||||||
|
fd_set SocketsReady; ///< Set containing handles of the sockets that are ready
|
||||||
|
int MaxSocket; ///< Maximum socket handle
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector::SocketSelector() :
|
||||||
|
m_impl(new SocketSelectorImpl)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector::SocketSelector(const SocketSelector& copy) :
|
||||||
|
m_impl(new SocketSelectorImpl(*copy.m_impl))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector::~SocketSelector()
|
||||||
|
{
|
||||||
|
delete m_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void SocketSelector::add(Socket& socket)
|
||||||
|
{
|
||||||
|
SocketHandle handle = socket.getHandle();
|
||||||
|
if (handle != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
FD_SET(handle, &m_impl->AllSockets);
|
||||||
|
|
||||||
|
int size = static_cast<int>(handle);
|
||||||
|
if (size > m_impl->MaxSocket)
|
||||||
|
m_impl->MaxSocket = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void SocketSelector::remove(Socket& socket)
|
||||||
|
{
|
||||||
|
FD_CLR(socket.getHandle(), &m_impl->AllSockets);
|
||||||
|
FD_CLR(socket.getHandle(), &m_impl->SocketsReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void SocketSelector::clear()
|
||||||
|
{
|
||||||
|
FD_ZERO(&m_impl->AllSockets);
|
||||||
|
FD_ZERO(&m_impl->SocketsReady);
|
||||||
|
|
||||||
|
m_impl->MaxSocket = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool SocketSelector::wait(Time timeout)
|
||||||
|
{
|
||||||
|
// Setup the timeout
|
||||||
|
timeval time;
|
||||||
|
time.tv_sec = static_cast<long>(timeout.asMicroseconds() / 1000000);
|
||||||
|
time.tv_usec = static_cast<long>(timeout.asMicroseconds() % 1000000);
|
||||||
|
|
||||||
|
// Initialize the set that will contain the sockets that are ready
|
||||||
|
m_impl->SocketsReady = m_impl->AllSockets;
|
||||||
|
|
||||||
|
// Wait until one of the sockets is ready for reading, or timeout is reached
|
||||||
|
int count = select(m_impl->MaxSocket + 1, &m_impl->SocketsReady, NULL, NULL, timeout != Time::Zero ? &time : NULL);
|
||||||
|
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool SocketSelector::isReady(Socket& socket) const
|
||||||
|
{
|
||||||
|
return FD_ISSET(socket.getHandle(), &m_impl->SocketsReady) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector& SocketSelector::operator =(const SocketSelector& right)
|
||||||
|
{
|
||||||
|
SocketSelector temp(right);
|
||||||
|
|
||||||
|
std::swap(m_impl, temp.m_impl);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -1,519 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/SocketTCP.hpp>
|
|
||||||
#include <SFML/Network/IPAddress.hpp>
|
|
||||||
#include <SFML/Network/Packet.hpp>
|
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketTCP::SocketTCP()
|
|
||||||
{
|
|
||||||
Create(SocketHelper::InvalidSocket());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Change the blocking state of the socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SocketTCP::SetBlocking(bool Blocking)
|
|
||||||
{
|
|
||||||
// Make sure our socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
Create();
|
|
||||||
|
|
||||||
SocketHelper::SetBlocking(mySocket, Blocking);
|
|
||||||
myIsBlocking = Blocking;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Connect to another computer on a specified port
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout)
|
|
||||||
{
|
|
||||||
// Make sure our socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
Create();
|
|
||||||
|
|
||||||
// Build the host address
|
|
||||||
sockaddr_in SockAddr;
|
|
||||||
memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
|
|
||||||
SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str());
|
|
||||||
SockAddr.sin_family = AF_INET;
|
|
||||||
SockAddr.sin_port = htons(Port);
|
|
||||||
|
|
||||||
if (Timeout <= 0)
|
|
||||||
{
|
|
||||||
// ----- We're not using a timeout : just try to connect -----
|
|
||||||
|
|
||||||
if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
|
|
||||||
{
|
|
||||||
// Failed to connect
|
|
||||||
return SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connection succeeded
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// ----- We're using a timeout : we'll need a few tricks to make it work -----
|
|
||||||
|
|
||||||
// Save the previous blocking state
|
|
||||||
bool IsBlocking = myIsBlocking;
|
|
||||||
|
|
||||||
// Switch to non-blocking to enable our connection timeout
|
|
||||||
if (IsBlocking)
|
|
||||||
SetBlocking(false);
|
|
||||||
|
|
||||||
// Try to connect to host
|
|
||||||
if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0)
|
|
||||||
{
|
|
||||||
// We got instantly connected! (it may no happen a lot...)
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the error status
|
|
||||||
Socket::Status Status = SocketHelper::GetErrorStatus();
|
|
||||||
|
|
||||||
// If we were in non-blocking mode, return immediatly
|
|
||||||
if (!IsBlocking)
|
|
||||||
return Status;
|
|
||||||
|
|
||||||
// Otherwise, wait until something happens to our socket (success, timeout or error)
|
|
||||||
if (Status == Socket::NotReady)
|
|
||||||
{
|
|
||||||
// Setup the selector
|
|
||||||
fd_set Selector;
|
|
||||||
FD_ZERO(&Selector);
|
|
||||||
FD_SET(mySocket, &Selector);
|
|
||||||
|
|
||||||
// Setup the timeout
|
|
||||||
timeval Time;
|
|
||||||
Time.tv_sec = static_cast<long>(Timeout);
|
|
||||||
Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
|
|
||||||
|
|
||||||
// Wait for something to write on our socket (which means that the connection request has returned)
|
|
||||||
if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0)
|
|
||||||
{
|
|
||||||
// At this point the connection may have been either accepted or refused.
|
|
||||||
// To know whether it's a success or a failure, we try to retrieve the name of the connected peer
|
|
||||||
SocketHelper::LengthType Size = sizeof(SockAddr);
|
|
||||||
if (getpeername(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) != -1)
|
|
||||||
{
|
|
||||||
// Connection accepted
|
|
||||||
Status = Socket::Done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Connection failed
|
|
||||||
Status = SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Failed to connect before timeout is over
|
|
||||||
Status = SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch back to blocking mode
|
|
||||||
SetBlocking(true);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Listen to a specified port for incoming data or connections
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketTCP::Listen(unsigned short Port)
|
|
||||||
{
|
|
||||||
// Make sure our socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
Create();
|
|
||||||
|
|
||||||
// Build the address
|
|
||||||
sockaddr_in SockAddr;
|
|
||||||
memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
|
|
||||||
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
SockAddr.sin_family = AF_INET;
|
|
||||||
SockAddr.sin_port = htons(Port);
|
|
||||||
|
|
||||||
// Bind the socket to the specified port
|
|
||||||
if (bind(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
|
|
||||||
{
|
|
||||||
// Not likely to happen, but...
|
|
||||||
std::cerr << "Failed to bind socket to port " << Port << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen to the bound port
|
|
||||||
if (listen(mySocket, 0) == -1)
|
|
||||||
{
|
|
||||||
// Oops, socket is deaf
|
|
||||||
std::cerr << "Failed to listen to port " << Port << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Wait for a connection (must be listening to a port).
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketTCP::Accept(SocketTCP& Connected, IPAddress* Address)
|
|
||||||
{
|
|
||||||
// Address that will be filled with client informations
|
|
||||||
sockaddr_in ClientAddress;
|
|
||||||
SocketHelper::LengthType Length = sizeof(ClientAddress);
|
|
||||||
|
|
||||||
// Accept a new connection
|
|
||||||
Connected = accept(mySocket, reinterpret_cast<sockaddr*>(&ClientAddress), &Length);
|
|
||||||
|
|
||||||
// Check errors
|
|
||||||
if (!Connected.IsValid())
|
|
||||||
{
|
|
||||||
if (Address)
|
|
||||||
*Address = IPAddress();
|
|
||||||
|
|
||||||
return SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill address if requested
|
|
||||||
if (Address)
|
|
||||||
*Address = IPAddress(inet_ntoa(ClientAddress.sin_addr));
|
|
||||||
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send an array of bytes to the host (must be connected first)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketTCP::Send(const char* Data, std::size_t Size)
|
|
||||||
{
|
|
||||||
// First check that socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
return Socket::Error;
|
|
||||||
|
|
||||||
// Check parameters
|
|
||||||
if (Data && Size)
|
|
||||||
{
|
|
||||||
// Loop until every byte has been sent
|
|
||||||
int Sent = 0;
|
|
||||||
int SizeToSend = static_cast<int>(Size);
|
|
||||||
for (int Length = 0; Length < SizeToSend; Length += Sent)
|
|
||||||
{
|
|
||||||
// Send a chunk of data
|
|
||||||
Sent = send(mySocket, Data + Length, SizeToSend - Length, 0);
|
|
||||||
|
|
||||||
// Check if an error occured
|
|
||||||
if (Sent <= 0)
|
|
||||||
return SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error...
|
|
||||||
std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
|
|
||||||
return Socket::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive an array of bytes from the host (must be connected first).
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived)
|
|
||||||
{
|
|
||||||
// First clear the size received
|
|
||||||
SizeReceived = 0;
|
|
||||||
|
|
||||||
// Check that socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
return Socket::Error;
|
|
||||||
|
|
||||||
// Check parameters
|
|
||||||
if (Data && MaxSize)
|
|
||||||
{
|
|
||||||
// Receive a chunk of bytes
|
|
||||||
int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
|
|
||||||
|
|
||||||
// Check the number of bytes received
|
|
||||||
if (Received > 0)
|
|
||||||
{
|
|
||||||
SizeReceived = static_cast<std::size_t>(Received);
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
else if (Received == 0)
|
|
||||||
{
|
|
||||||
return Socket::Disconnected;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error...
|
|
||||||
std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
|
|
||||||
return Socket::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a packet of data to the host (must be connected first)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketTCP::Send(Packet& PacketToSend)
|
|
||||||
{
|
|
||||||
// Get the data to send from the packet
|
|
||||||
std::size_t DataSize = 0;
|
|
||||||
const char* Data = PacketToSend.OnSend(DataSize);
|
|
||||||
|
|
||||||
// Send the packet size
|
|
||||||
Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
|
|
||||||
Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize));
|
|
||||||
|
|
||||||
// Send the packet data
|
|
||||||
if (PacketSize > 0)
|
|
||||||
{
|
|
||||||
return Send(Data, DataSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive a packet from the host (must be connected first).
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
|
|
||||||
{
|
|
||||||
// We start by getting the size of the incoming packet
|
|
||||||
Uint32 PacketSize = 0;
|
|
||||||
std::size_t Received = 0;
|
|
||||||
if (myPendingPacketSize < 0)
|
|
||||||
{
|
|
||||||
// Loop until we've received the entire size of the packet
|
|
||||||
// (even a 4 bytes variable may be received in more than one call)
|
|
||||||
while (myPendingHeaderSize < sizeof(myPendingHeader))
|
|
||||||
{
|
|
||||||
char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
|
|
||||||
Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received);
|
|
||||||
myPendingHeaderSize += Received;
|
|
||||||
|
|
||||||
if (Status != Socket::Done)
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
PacketSize = ntohl(myPendingHeader);
|
|
||||||
myPendingHeaderSize = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// There is a pending packet : we already know its size
|
|
||||||
PacketSize = myPendingPacketSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then loop until we receive all the packet data
|
|
||||||
char Buffer[1024];
|
|
||||||
while (myPendingPacket.size() < PacketSize)
|
|
||||||
{
|
|
||||||
// Receive a chunk of data
|
|
||||||
std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
|
|
||||||
Socket::Status Status = Receive(Buffer, SizeToGet, Received);
|
|
||||||
if (Status != Socket::Done)
|
|
||||||
{
|
|
||||||
// We must save the size of the pending packet until we can receive its content
|
|
||||||
if (Status == Socket::NotReady)
|
|
||||||
myPendingPacketSize = PacketSize;
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append it into the packet
|
|
||||||
if (Received > 0)
|
|
||||||
{
|
|
||||||
myPendingPacket.resize(myPendingPacket.size() + Received);
|
|
||||||
char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
|
|
||||||
memcpy(Begin, Buffer, Received);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
|
|
||||||
PacketToReceive.Clear();
|
|
||||||
if (!myPendingPacket.empty())
|
|
||||||
PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
|
|
||||||
myPendingPacket.clear();
|
|
||||||
myPendingPacketSize = -1;
|
|
||||||
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Close the socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketTCP::Close()
|
|
||||||
{
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
if (!SocketHelper::Close(mySocket))
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to close socket" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mySocket = SocketHelper::InvalidSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
myIsBlocking = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Check if the socket is in a valid state ; this function
|
|
||||||
/// can be called any time to check if the socket is OK
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketTCP::IsValid() const
|
|
||||||
{
|
|
||||||
return mySocket != SocketHelper::InvalidSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator ==
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketTCP::operator ==(const SocketTCP& Other) const
|
|
||||||
{
|
|
||||||
return mySocket == Other.mySocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator !=
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketTCP::operator !=(const SocketTCP& Other) const
|
|
||||||
{
|
|
||||||
return mySocket != Other.mySocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator <.
|
|
||||||
/// Provided for compatibility with standard containers, as
|
|
||||||
/// comparing two sockets doesn't make much sense...
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketTCP::operator <(const SocketTCP& Other) const
|
|
||||||
{
|
|
||||||
return mySocket < Other.mySocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Construct the socket from a socket descriptor
|
|
||||||
/// (for internal use only)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor)
|
|
||||||
{
|
|
||||||
Create(Descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Create the socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SocketTCP::Create(SocketHelper::SocketType Descriptor)
|
|
||||||
{
|
|
||||||
// Use the given socket descriptor, or get a new one
|
|
||||||
mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
myIsBlocking = true;
|
|
||||||
|
|
||||||
// Reset the pending packet
|
|
||||||
myPendingHeaderSize = 0;
|
|
||||||
myPendingPacket.clear();
|
|
||||||
myPendingPacketSize = -1;
|
|
||||||
|
|
||||||
// Setup default options
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
int Yes = 1;
|
|
||||||
#ifndef SFML_SYSTEM_WINDOWS
|
|
||||||
/* We must disable this in order to detect if ports are being used by other apps, or
|
|
||||||
other instances of dolphin. This is also disabled in SFML 2.0, see
|
|
||||||
http://www.sfml-dev.org/forum/viewtopic.php?t=3388
|
|
||||||
...In fact, SO_REUSEADDR is only unsafe on Windows. See:
|
|
||||||
http://stackoverflow.com/questions/14388706
|
|
||||||
*/
|
|
||||||
// To avoid the "Address already in use" error message when trying to bind to the same port
|
|
||||||
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; "
|
|
||||||
<< "binding to a same port may fail if too fast" << std::endl;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Disable the Nagle algorithm (ie. removes buffering of TCP packets)
|
|
||||||
if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; "
|
|
||||||
<< "all your TCP packets will be buffered" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set blocking by default (should always be the case anyway)
|
|
||||||
SetBlocking(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sf
|
|
|
@ -1,433 +0,0 @@
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// SFML - Simple and Fast Multimedia Library
|
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it freely,
|
|
||||||
// subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented;
|
|
||||||
// you must not claim that you wrote the original software.
|
|
||||||
// If you use this software in a product, an acknowledgment
|
|
||||||
// in the product documentation would be appreciated but is not required.
|
|
||||||
//
|
|
||||||
// 2. Altered source versions must be plainly marked as such,
|
|
||||||
// and must not be misrepresented as being the original software.
|
|
||||||
//
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// Headers
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
#include <SFML/Network/SocketUDP.hpp>
|
|
||||||
#include <SFML/Network/IPAddress.hpp>
|
|
||||||
#include <SFML/Network/Packet.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
|
||||||
{
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Default constructor
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketUDP::SocketUDP()
|
|
||||||
{
|
|
||||||
Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Change the blocking state of the socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SocketUDP::SetBlocking(bool Blocking)
|
|
||||||
{
|
|
||||||
// Make sure our socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
Create();
|
|
||||||
|
|
||||||
SocketHelper::SetBlocking(mySocket, Blocking);
|
|
||||||
myIsBlocking = Blocking;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Bind the socket to a specific port
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::Bind(unsigned short Port)
|
|
||||||
{
|
|
||||||
// Check if the socket is already bound to the specified port
|
|
||||||
if (myPort != Port)
|
|
||||||
{
|
|
||||||
// If the socket was previously bound to another port, we need to unbind it first
|
|
||||||
Unbind();
|
|
||||||
|
|
||||||
if (Port != 0)
|
|
||||||
{
|
|
||||||
// Build an address with the specified port
|
|
||||||
sockaddr_in Addr;
|
|
||||||
Addr.sin_family = AF_INET;
|
|
||||||
Addr.sin_port = htons(Port);
|
|
||||||
Addr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero));
|
|
||||||
|
|
||||||
// Bind the socket to the port
|
|
||||||
if (bind(mySocket, reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr)) == -1)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to bind the socket to port " << Port << std::endl;
|
|
||||||
myPort = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the new port
|
|
||||||
myPort = Port;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Unbind the socket to its previous port
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::Unbind()
|
|
||||||
{
|
|
||||||
// To unbind the socket, we just recreate it
|
|
||||||
if (myPort != 0)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
Create();
|
|
||||||
myPort = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send an array of bytes
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port)
|
|
||||||
{
|
|
||||||
// Make sure the socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
Create();
|
|
||||||
|
|
||||||
// Check parameters
|
|
||||||
if (Data && Size)
|
|
||||||
{
|
|
||||||
// Build the target address
|
|
||||||
sockaddr_in Target;
|
|
||||||
Target.sin_family = AF_INET;
|
|
||||||
Target.sin_port = htons(Port);
|
|
||||||
Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str());
|
|
||||||
memset(Target.sin_zero, 0, sizeof(Target.sin_zero));
|
|
||||||
|
|
||||||
// Loop until every byte has been sent
|
|
||||||
int Sent = 0;
|
|
||||||
int SizeToSend = static_cast<int>(Size);
|
|
||||||
for (int Length = 0; Length < SizeToSend; Length += Sent)
|
|
||||||
{
|
|
||||||
// Send a chunk of data
|
|
||||||
Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target));
|
|
||||||
|
|
||||||
// Check errors
|
|
||||||
if (Sent <= 0)
|
|
||||||
return SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error...
|
|
||||||
std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
|
|
||||||
return Socket::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive an array of bytes.
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address, unsigned short& Port)
|
|
||||||
{
|
|
||||||
// First clear the size received
|
|
||||||
SizeReceived = 0;
|
|
||||||
|
|
||||||
// Make sure the socket is bound to a port
|
|
||||||
if (myPort == 0)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl;
|
|
||||||
return Socket::Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the socket is valid
|
|
||||||
if (!IsValid())
|
|
||||||
Create();
|
|
||||||
|
|
||||||
// Check parameters
|
|
||||||
if (Data && MaxSize)
|
|
||||||
{
|
|
||||||
// Data that will be filled with the other computer's address
|
|
||||||
sockaddr_in Sender;
|
|
||||||
Sender.sin_family = AF_INET;
|
|
||||||
Sender.sin_port = 0;
|
|
||||||
Sender.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero));
|
|
||||||
SocketHelper::LengthType SenderSize = sizeof(Sender);
|
|
||||||
|
|
||||||
// Receive a chunk of bytes
|
|
||||||
int Received = recvfrom(mySocket, Data, static_cast<int>(MaxSize), 0, reinterpret_cast<sockaddr*>(&Sender), &SenderSize);
|
|
||||||
|
|
||||||
// Check the number of bytes received
|
|
||||||
if (Received > 0)
|
|
||||||
{
|
|
||||||
Address = IPAddress(inet_ntoa(Sender.sin_addr));
|
|
||||||
Port = ntohs(Sender.sin_port);
|
|
||||||
SizeReceived = static_cast<std::size_t>(Received);
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Address = IPAddress();
|
|
||||||
Port = 0;
|
|
||||||
return Received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error...
|
|
||||||
std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
|
|
||||||
return Socket::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Send a packet of data
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port)
|
|
||||||
{
|
|
||||||
// Get the data to send from the packet
|
|
||||||
std::size_t DataSize = 0;
|
|
||||||
const char* Data = PacketToSend.OnSend(DataSize);
|
|
||||||
|
|
||||||
// Send the packet size
|
|
||||||
Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
|
|
||||||
Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port);
|
|
||||||
|
|
||||||
// Send the packet data
|
|
||||||
if (PacketSize > 0)
|
|
||||||
{
|
|
||||||
return Send(Data, DataSize, Address, Port);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Receive a packet.
|
|
||||||
/// This function will block if the socket is blocking
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port)
|
|
||||||
{
|
|
||||||
// We start by getting the size of the incoming packet
|
|
||||||
Uint32 PacketSize = 0;
|
|
||||||
std::size_t Received = 0;
|
|
||||||
if (myPendingPacketSize < 0)
|
|
||||||
{
|
|
||||||
// Loop until we've received the entire size of the packet
|
|
||||||
// (even a 4 bytes variable may be received in more than one call)
|
|
||||||
while (myPendingHeaderSize < sizeof(myPendingHeader))
|
|
||||||
{
|
|
||||||
char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
|
|
||||||
Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received, Address, Port);
|
|
||||||
myPendingHeaderSize += Received;
|
|
||||||
|
|
||||||
if (Status != Socket::Done)
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
PacketSize = ntohl(myPendingHeader);
|
|
||||||
myPendingHeaderSize = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// There is a pending packet : we already know its size
|
|
||||||
PacketSize = myPendingPacketSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use another address instance for receiving the packet data ;
|
|
||||||
// chunks of data coming from a different sender will be discarded (and lost...)
|
|
||||||
IPAddress Sender;
|
|
||||||
unsigned short SenderPort;
|
|
||||||
|
|
||||||
// Then loop until we receive all the packet data
|
|
||||||
char Buffer[1024];
|
|
||||||
while (myPendingPacket.size() < PacketSize)
|
|
||||||
{
|
|
||||||
// Receive a chunk of data
|
|
||||||
std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
|
|
||||||
Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender, SenderPort);
|
|
||||||
if (Status != Socket::Done)
|
|
||||||
{
|
|
||||||
// We must save the size of the pending packet until we can receive its content
|
|
||||||
if (Status == Socket::NotReady)
|
|
||||||
myPendingPacketSize = PacketSize;
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append it into the packet
|
|
||||||
if ((Sender == Address) && (SenderPort == Port) && (Received > 0))
|
|
||||||
{
|
|
||||||
myPendingPacket.resize(myPendingPacket.size() + Received);
|
|
||||||
char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
|
|
||||||
memcpy(Begin, Buffer, Received);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
|
|
||||||
PacketToReceive.Clear();
|
|
||||||
if (!myPendingPacket.empty())
|
|
||||||
PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
|
|
||||||
myPendingPacket.clear();
|
|
||||||
myPendingPacketSize = -1;
|
|
||||||
|
|
||||||
return Socket::Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Close the socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::Close()
|
|
||||||
{
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
if (!SocketHelper::Close(mySocket))
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to close socket" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mySocket = SocketHelper::InvalidSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
myPort = 0;
|
|
||||||
myIsBlocking = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Check if the socket is in a valid state ; this function
|
|
||||||
/// can be called any time to check if the socket is OK
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::IsValid() const
|
|
||||||
{
|
|
||||||
return mySocket != SocketHelper::InvalidSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Get the port the socket is currently bound to
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
unsigned short SocketUDP::GetPort() const
|
|
||||||
{
|
|
||||||
return myPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator ==
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::operator ==(const SocketUDP& Other) const
|
|
||||||
{
|
|
||||||
return mySocket == Other.mySocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator !=
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::operator !=(const SocketUDP& Other) const
|
|
||||||
{
|
|
||||||
return mySocket != Other.mySocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Comparison operator <.
|
|
||||||
/// Provided for compatibility with standard containers, as
|
|
||||||
/// comparing two sockets doesn't make much sense...
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketUDP::operator <(const SocketUDP& Other) const
|
|
||||||
{
|
|
||||||
return mySocket < Other.mySocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Construct the socket from a socket descriptor
|
|
||||||
/// (for internal use only)
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor)
|
|
||||||
{
|
|
||||||
Create(Descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
/// Create the socket
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SocketUDP::Create(SocketHelper::SocketType Descriptor)
|
|
||||||
{
|
|
||||||
// Use the given socket descriptor, or get a new one
|
|
||||||
mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0);
|
|
||||||
myIsBlocking = true;
|
|
||||||
|
|
||||||
// Clear the last port used
|
|
||||||
myPort = 0;
|
|
||||||
|
|
||||||
// Reset the pending packet
|
|
||||||
myPendingHeaderSize = 0;
|
|
||||||
myPendingPacket.clear();
|
|
||||||
myPendingPacketSize = -1;
|
|
||||||
|
|
||||||
// Setup default options
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
// To avoid the "Address already in use" error message when trying to bind to the same port
|
|
||||||
int Yes = 1;
|
|
||||||
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to set socket option \"reuse address\" ; "
|
|
||||||
<< "binding to a same port may fail if too fast" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable broadcast by default
|
|
||||||
if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set blocking by default (should always be the case anyway)
|
|
||||||
SetBlocking(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace sf
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/TcpListener.hpp>
|
||||||
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpListener::TcpListener() :
|
||||||
|
Socket(Tcp)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short TcpListener::getLocalPort() const
|
||||||
|
{
|
||||||
|
if (getHandle() != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
// Retrieve informations about the local end of the socket
|
||||||
|
sockaddr_in address;
|
||||||
|
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||||
|
if (getsockname(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||||
|
{
|
||||||
|
return ntohs(address.sin_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We failed to retrieve the port
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpListener::listen(unsigned short port)
|
||||||
|
{
|
||||||
|
// Create the internal socket if it doesn't exist
|
||||||
|
create();
|
||||||
|
|
||||||
|
// Bind the socket to the specified port
|
||||||
|
sockaddr_in address = priv::SocketImpl::createAddress(INADDR_ANY, port);
|
||||||
|
if (bind(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||||
|
{
|
||||||
|
// Not likely to happen, but...
|
||||||
|
err() << "Failed to bind listener socket to port " << port << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen to the bound port
|
||||||
|
if (::listen(getHandle(), 0) == -1)
|
||||||
|
{
|
||||||
|
// Oops, socket is deaf
|
||||||
|
err() << "Failed to listen to port " << port << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void TcpListener::close()
|
||||||
|
{
|
||||||
|
// Simply close the socket
|
||||||
|
Socket::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpListener::accept(TcpSocket& socket)
|
||||||
|
{
|
||||||
|
// Make sure that we're listening
|
||||||
|
if (getHandle() == priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
err() << "Failed to accept a new connection, the socket is not listening" << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept a new connection
|
||||||
|
sockaddr_in address;
|
||||||
|
priv::SocketImpl::AddrLength length = sizeof(address);
|
||||||
|
SocketHandle remote = ::accept(getHandle(), reinterpret_cast<sockaddr*>(&address), &length);
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (remote == priv::SocketImpl::invalidSocket())
|
||||||
|
return priv::SocketImpl::getErrorStatus();
|
||||||
|
|
||||||
|
// Initialize the new connected socket
|
||||||
|
socket.close();
|
||||||
|
socket.create(remote);
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -0,0 +1,381 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
#include <SFML/Network/IPAddress.hpp>
|
||||||
|
#include <SFML/Network/Packet.hpp>
|
||||||
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Define the low-level send/receive flags, which depend on the OS
|
||||||
|
#ifdef SFML_SYSTEM_LINUX
|
||||||
|
const int flags = MSG_NOSIGNAL;
|
||||||
|
#else
|
||||||
|
const int flags = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpSocket::TcpSocket() :
|
||||||
|
Socket(Tcp)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short TcpSocket::getLocalPort() const
|
||||||
|
{
|
||||||
|
if (getHandle() != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
// Retrieve informations about the local end of the socket
|
||||||
|
sockaddr_in address;
|
||||||
|
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||||
|
if (getsockname(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||||
|
{
|
||||||
|
return ntohs(address.sin_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We failed to retrieve the port
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
IpAddress TcpSocket::getRemoteAddress() const
|
||||||
|
{
|
||||||
|
if (getHandle() != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
// Retrieve informations about the remote end of the socket
|
||||||
|
sockaddr_in address;
|
||||||
|
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||||
|
if (getpeername(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||||
|
{
|
||||||
|
return IpAddress(ntohl(address.sin_addr.s_addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We failed to retrieve the address
|
||||||
|
return IpAddress::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short TcpSocket::getRemotePort() const
|
||||||
|
{
|
||||||
|
if (getHandle() != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
// Retrieve informations about the remote end of the socket
|
||||||
|
sockaddr_in address;
|
||||||
|
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||||
|
if (getpeername(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||||
|
{
|
||||||
|
return ntohs(address.sin_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We failed to retrieve the port
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpSocket::connect(const IpAddress& remoteAddress, unsigned short remotePort, Time timeout)
|
||||||
|
{
|
||||||
|
// Create the internal socket if it doesn't exist
|
||||||
|
create();
|
||||||
|
|
||||||
|
// Create the remote address
|
||||||
|
sockaddr_in address = priv::SocketImpl::createAddress(remoteAddress.toInteger(), remotePort);
|
||||||
|
|
||||||
|
if (timeout <= Time::Zero)
|
||||||
|
{
|
||||||
|
// ----- We're not using a timeout: just try to connect -----
|
||||||
|
|
||||||
|
// Connect the socket
|
||||||
|
if (::connect(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||||
|
return priv::SocketImpl::getErrorStatus();
|
||||||
|
|
||||||
|
// Connection succeeded
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ----- We're using a timeout: we'll need a few tricks to make it work -----
|
||||||
|
|
||||||
|
// Save the previous blocking state
|
||||||
|
bool blocking = isBlocking();
|
||||||
|
|
||||||
|
// Switch to non-blocking to enable our connection timeout
|
||||||
|
if (blocking)
|
||||||
|
setBlocking(false);
|
||||||
|
|
||||||
|
// Try to connect to the remote address
|
||||||
|
if (::connect(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) >= 0)
|
||||||
|
{
|
||||||
|
// We got instantly connected! (it may no happen a lot...)
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the error status
|
||||||
|
Status status = priv::SocketImpl::getErrorStatus();
|
||||||
|
|
||||||
|
// If we were in non-blocking mode, return immediatly
|
||||||
|
if (!blocking)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// Otherwise, wait until something happens to our socket (success, timeout or error)
|
||||||
|
if (status == Socket::NotReady)
|
||||||
|
{
|
||||||
|
// Setup the selector
|
||||||
|
fd_set selector;
|
||||||
|
FD_ZERO(&selector);
|
||||||
|
FD_SET(getHandle(), &selector);
|
||||||
|
|
||||||
|
// Setup the timeout
|
||||||
|
timeval time;
|
||||||
|
time.tv_sec = static_cast<long>(timeout.asMicroseconds() / 1000000);
|
||||||
|
time.tv_usec = static_cast<long>(timeout.asMicroseconds() % 1000000);
|
||||||
|
|
||||||
|
// Wait for something to write on our socket (which means that the connection request has returned)
|
||||||
|
if (select(static_cast<int>(getHandle() + 1), NULL, &selector, NULL, &time) > 0)
|
||||||
|
{
|
||||||
|
// At this point the connection may have been either accepted or refused.
|
||||||
|
// To know whether it's a success or a failure, we must check the address of the connected peer
|
||||||
|
if (getRemoteAddress() != sf::IpAddress::None)
|
||||||
|
{
|
||||||
|
// Connection accepted
|
||||||
|
status = Done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Connection refused
|
||||||
|
status = priv::SocketImpl::getErrorStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Failed to connect before timeout is over
|
||||||
|
status = priv::SocketImpl::getErrorStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch back to blocking mode
|
||||||
|
setBlocking(true);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void TcpSocket::disconnect()
|
||||||
|
{
|
||||||
|
// Close the socket
|
||||||
|
close();
|
||||||
|
|
||||||
|
// Reset the pending packet data
|
||||||
|
m_pendingPacket = PendingPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpSocket::send(const void* data, std::size_t size)
|
||||||
|
{
|
||||||
|
// Check the parameters
|
||||||
|
if (!data || (size == 0))
|
||||||
|
{
|
||||||
|
err() << "Cannot send data over the network (no data to send)" << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop until every byte has been sent
|
||||||
|
int sent = 0;
|
||||||
|
int sizeToSend = static_cast<int>(size);
|
||||||
|
for (int length = 0; length < sizeToSend; length += sent)
|
||||||
|
{
|
||||||
|
// Send a chunk of data
|
||||||
|
sent = ::send(getHandle(), static_cast<const char*>(data) + length, sizeToSend - length, flags);
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (sent < 0)
|
||||||
|
return priv::SocketImpl::getErrorStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpSocket::receive(void* data, std::size_t size, std::size_t& received)
|
||||||
|
{
|
||||||
|
// First clear the variables to fill
|
||||||
|
received = 0;
|
||||||
|
|
||||||
|
// Check the destination buffer
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
err() << "Cannot receive data from the network (the destination buffer is invalid)" << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive a chunk of bytes
|
||||||
|
int sizeReceived = recv(getHandle(), static_cast<char*>(data), static_cast<int>(size), flags);
|
||||||
|
|
||||||
|
// Check the number of bytes received
|
||||||
|
if (sizeReceived > 0)
|
||||||
|
{
|
||||||
|
received = static_cast<std::size_t>(sizeReceived);
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
else if (sizeReceived == 0)
|
||||||
|
{
|
||||||
|
return Socket::Disconnected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return priv::SocketImpl::getErrorStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpSocket::send(Packet& packet)
|
||||||
|
{
|
||||||
|
// TCP is a stream protocol, it doesn't preserve messages boundaries.
|
||||||
|
// This means that we have to send the packet size first, so that the
|
||||||
|
// receiver knows the actual end of the packet in the data stream.
|
||||||
|
|
||||||
|
// We allocate an extra memory block so that the size can be sent
|
||||||
|
// together with the data in a single call. This may seem inefficient,
|
||||||
|
// but it is actually required to avoid partial send, which could cause
|
||||||
|
// data corruption on the receiving end.
|
||||||
|
|
||||||
|
// Get the data to send from the packet
|
||||||
|
std::size_t size = 0;
|
||||||
|
const void* data = packet.onSend(size);
|
||||||
|
|
||||||
|
// First convert the packet size to network byte order
|
||||||
|
Uint32 packetSize = htonl(static_cast<Uint32>(size));
|
||||||
|
|
||||||
|
// Allocate memory for the data block to send
|
||||||
|
std::vector<char> blockToSend(sizeof(packetSize) + size);
|
||||||
|
|
||||||
|
// Copy the packet size and data into the block to send
|
||||||
|
std::memcpy(&blockToSend[0], &packetSize, sizeof(packetSize));
|
||||||
|
if (size > 0)
|
||||||
|
std::memcpy(&blockToSend[0] + sizeof(packetSize), data, size);
|
||||||
|
|
||||||
|
// Send the data block
|
||||||
|
return send(&blockToSend[0], blockToSend.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpSocket::receive(Packet& packet)
|
||||||
|
{
|
||||||
|
// First clear the variables to fill
|
||||||
|
packet.clear();
|
||||||
|
|
||||||
|
// We start by getting the size of the incoming packet
|
||||||
|
Uint32 packetSize = 0;
|
||||||
|
std::size_t received = 0;
|
||||||
|
if (m_pendingPacket.SizeReceived < sizeof(m_pendingPacket.Size))
|
||||||
|
{
|
||||||
|
// Loop until we've received the entire size of the packet
|
||||||
|
// (even a 4 byte variable may be received in more than one call)
|
||||||
|
while (m_pendingPacket.SizeReceived < sizeof(m_pendingPacket.Size))
|
||||||
|
{
|
||||||
|
char* data = reinterpret_cast<char*>(&m_pendingPacket.Size) + m_pendingPacket.SizeReceived;
|
||||||
|
Status status = receive(data, sizeof(m_pendingPacket.Size) - m_pendingPacket.SizeReceived, received);
|
||||||
|
m_pendingPacket.SizeReceived += received;
|
||||||
|
|
||||||
|
if (status != Done)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The packet size has been fully received
|
||||||
|
packetSize = ntohl(m_pendingPacket.Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The packet size has already been received in a previous call
|
||||||
|
packetSize = ntohl(m_pendingPacket.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop until we receive all the packet data
|
||||||
|
char buffer[1024];
|
||||||
|
while (m_pendingPacket.Data.size() < packetSize)
|
||||||
|
{
|
||||||
|
// Receive a chunk of data
|
||||||
|
std::size_t sizeToGet = std::min(static_cast<std::size_t>(packetSize - m_pendingPacket.Data.size()), sizeof(buffer));
|
||||||
|
Status status = receive(buffer, sizeToGet, received);
|
||||||
|
if (status != Done)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// Append it into the packet
|
||||||
|
if (received > 0)
|
||||||
|
{
|
||||||
|
m_pendingPacket.Data.resize(m_pendingPacket.Data.size() + received);
|
||||||
|
char* begin = &m_pendingPacket.Data[0] + m_pendingPacket.Data.size() - received;
|
||||||
|
std::memcpy(begin, buffer, received);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have received all the packet data: we can copy it to the user packet
|
||||||
|
if (!m_pendingPacket.Data.empty())
|
||||||
|
packet.onReceive(&m_pendingPacket.Data[0], m_pendingPacket.Data.size());
|
||||||
|
|
||||||
|
// Clear the pending packet data
|
||||||
|
m_pendingPacket = PendingPacket();
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpSocket::PendingPacket::PendingPacket() :
|
||||||
|
Size (0),
|
||||||
|
SizeReceived(0),
|
||||||
|
Data ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -0,0 +1,193 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/UdpSocket.hpp>
|
||||||
|
#include <SFML/Network/IPAddress.hpp>
|
||||||
|
#include <SFML/Network/Packet.hpp>
|
||||||
|
#include <SFML/Network/SocketImpl.hpp>
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
UdpSocket::UdpSocket() :
|
||||||
|
Socket (Udp),
|
||||||
|
m_buffer(MaxDatagramSize)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned short UdpSocket::getLocalPort() const
|
||||||
|
{
|
||||||
|
if (getHandle() != priv::SocketImpl::invalidSocket())
|
||||||
|
{
|
||||||
|
// Retrieve informations about the local end of the socket
|
||||||
|
sockaddr_in address;
|
||||||
|
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||||
|
if (getsockname(getHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||||
|
{
|
||||||
|
return ntohs(address.sin_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We failed to retrieve the port
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status UdpSocket::bind(unsigned short port)
|
||||||
|
{
|
||||||
|
// Create the internal socket if it doesn't exist
|
||||||
|
create();
|
||||||
|
|
||||||
|
// Bind the socket
|
||||||
|
sockaddr_in address = priv::SocketImpl::createAddress(INADDR_ANY, port);
|
||||||
|
if (::bind(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||||
|
{
|
||||||
|
err() << "Failed to bind socket to port " << port << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void UdpSocket::unbind()
|
||||||
|
{
|
||||||
|
// Simply close the socket
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status UdpSocket::send(const void* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort)
|
||||||
|
{
|
||||||
|
// Create the internal socket if it doesn't exist
|
||||||
|
create();
|
||||||
|
|
||||||
|
// Make sure that all the data will fit in one datagram
|
||||||
|
if (size > MaxDatagramSize)
|
||||||
|
{
|
||||||
|
err() << "Cannot send data over the network "
|
||||||
|
<< "(the number of bytes to send is greater than sf::UdpSocket::MaxDatagramSize)" << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the target address
|
||||||
|
sockaddr_in address = priv::SocketImpl::createAddress(remoteAddress.toInteger(), remotePort);
|
||||||
|
|
||||||
|
// Send the data (unlike TCP, all the data is always sent in one call)
|
||||||
|
int sent = sendto(getHandle(), static_cast<const char*>(data), static_cast<int>(size), 0, reinterpret_cast<sockaddr*>(&address), sizeof(address));
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (sent < 0)
|
||||||
|
return priv::SocketImpl::getErrorStatus();
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status UdpSocket::receive(void* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort)
|
||||||
|
{
|
||||||
|
// First clear the variables to fill
|
||||||
|
received = 0;
|
||||||
|
remoteAddress = IpAddress();
|
||||||
|
remotePort = 0;
|
||||||
|
|
||||||
|
// Check the destination buffer
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
err() << "Cannot receive data from the network (the destination buffer is invalid)" << std::endl;
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data that will be filled with the other computer's address
|
||||||
|
sockaddr_in address = priv::SocketImpl::createAddress(INADDR_ANY, 0);
|
||||||
|
|
||||||
|
// Receive a chunk of bytes
|
||||||
|
priv::SocketImpl::AddrLength addressSize = sizeof(address);
|
||||||
|
int sizeReceived = recvfrom(getHandle(), static_cast<char*>(data), static_cast<int>(size), 0, reinterpret_cast<sockaddr*>(&address), &addressSize);
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (sizeReceived < 0)
|
||||||
|
return priv::SocketImpl::getErrorStatus();
|
||||||
|
|
||||||
|
// Fill the sender informations
|
||||||
|
received = static_cast<std::size_t>(sizeReceived);
|
||||||
|
remoteAddress = IpAddress(ntohl(address.sin_addr.s_addr));
|
||||||
|
remotePort = ntohs(address.sin_port);
|
||||||
|
|
||||||
|
return Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status UdpSocket::send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort)
|
||||||
|
{
|
||||||
|
// UDP is a datagram-oriented protocol (as opposed to TCP which is a stream protocol).
|
||||||
|
// Sending one datagram is almost safe: it may be lost but if it's received, then its data
|
||||||
|
// is guaranteed to be ok. However, splitting a packet into multiple datagrams would be highly
|
||||||
|
// unreliable, since datagrams may be reordered, dropped or mixed between different sources.
|
||||||
|
// That's why SFML imposes a limit on packet size so that they can be sent in a single datagram.
|
||||||
|
// This also removes the overhead associated to packets -- there's no size to send in addition
|
||||||
|
// to the packet's data.
|
||||||
|
|
||||||
|
// Get the data to send from the packet
|
||||||
|
std::size_t size = 0;
|
||||||
|
const void* data = packet.onSend(size);
|
||||||
|
|
||||||
|
// Send it
|
||||||
|
return send(data, size, remoteAddress, remotePort);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status UdpSocket::receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort)
|
||||||
|
{
|
||||||
|
// See the detailed comment in send(Packet) above.
|
||||||
|
|
||||||
|
// Receive the datagram
|
||||||
|
std::size_t received = 0;
|
||||||
|
Status status = receive(&m_buffer[0], m_buffer.size(), received, remoteAddress, remotePort);
|
||||||
|
|
||||||
|
// If we received valid data, we can copy it to the user packet
|
||||||
|
packet.clear();
|
||||||
|
if ((status == Done) && (received > 0))
|
||||||
|
packet.onReceive(&m_buffer[0], received);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -25,48 +25,56 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
#include <SFML/Network/Unix/SocketImpl.hpp>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Return the value of the invalid socket
|
sockaddr_in SocketImpl::createAddress(Uint32 address, unsigned short port)
|
||||||
|
{
|
||||||
|
sockaddr_in addr;
|
||||||
|
std::memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||||
|
addr.sin_addr.s_addr = htonl(address);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
SocketHelper::SocketType SocketHelper::InvalidSocket()
|
SocketHandle SocketImpl::invalidSocket()
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Close / destroy a socket
|
void SocketImpl::close(SocketHandle sock)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketHelper::Close(SocketHelper::SocketType Socket)
|
|
||||||
{
|
{
|
||||||
return close(Socket) != -1;
|
::close(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set a socket as blocking or non-blocking
|
void SocketImpl::setBlocking(SocketHandle sock, bool block)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block)
|
|
||||||
{
|
{
|
||||||
int Status = fcntl(Socket, F_GETFL);
|
int status = fcntl(sock, F_GETFL);
|
||||||
if (Block)
|
if (block)
|
||||||
fcntl(Socket, F_SETFL, Status & ~O_NONBLOCK);
|
fcntl(sock, F_SETFL, status & ~O_NONBLOCK);
|
||||||
else
|
else
|
||||||
fcntl(Socket, F_SETFL, Status | O_NONBLOCK);
|
fcntl(sock, F_SETFL, status | O_NONBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the last socket error status
|
Socket::Status SocketImpl::getErrorStatus()
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketHelper::GetErrorStatus()
|
|
||||||
{
|
{
|
||||||
// The followings are sometimes equal to EWOULDBLOCK,
|
// The followings are sometimes equal to EWOULDBLOCK,
|
||||||
// so we have to make a special case for them in order
|
// so we have to make a special case for them in order
|
||||||
|
@ -82,8 +90,11 @@ Socket::Status SocketHelper::GetErrorStatus()
|
||||||
case ETIMEDOUT : return Socket::Disconnected;
|
case ETIMEDOUT : return Socket::Disconnected;
|
||||||
case ENETRESET : return Socket::Disconnected;
|
case ENETRESET : return Socket::Disconnected;
|
||||||
case ENOTCONN : return Socket::Disconnected;
|
case ENOTCONN : return Socket::Disconnected;
|
||||||
|
case EPIPE : return Socket::Disconnected;
|
||||||
default : return Socket::Error;
|
default : return Socket::Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -22,12 +22,13 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef SFML_SOCKETHELPERUNIX_HPP
|
#ifndef SFML_SOCKETIMPL_HPP
|
||||||
#define SFML_SOCKETHELPERUNIX_HPP
|
#define SFML_SOCKETIMPL_HPP
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
@ -39,47 +40,57 @@
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// This class defines helper functions to do all the
|
/// \brief Helper class implementing all the non-portable
|
||||||
/// non-portable socket stuff. This class is meant for internal
|
/// socket stuff; this is the Unix version
|
||||||
/// use only
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API SocketHelper
|
class SocketImpl
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Define some socket types
|
// Types
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
typedef int SocketType;
|
typedef socklen_t AddrLength;
|
||||||
typedef socklen_t LengthType;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Return the value of the invalid socket
|
/// \brief Create an internal sockaddr_in address
|
||||||
///
|
///
|
||||||
/// \return Unique value of the invalid socket
|
/// \param address Target address
|
||||||
|
/// \param port Target port
|
||||||
|
///
|
||||||
|
/// \return sockaddr_in ready to be used by socket functions
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static SocketType InvalidSocket();
|
static sockaddr_in createAddress(Uint32 address, unsigned short port);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Close / destroy a socket
|
/// \brief Return the value of the invalid socket
|
||||||
///
|
///
|
||||||
/// \param Socket : Socket to close
|
/// \return Special value of the invalid socket
|
||||||
///
|
|
||||||
/// \return True on success
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static bool Close(SocketType Socket);
|
static SocketHandle invalidSocket();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set a socket as blocking or non-blocking
|
/// \brief Close and destroy a socket
|
||||||
///
|
///
|
||||||
/// \param Socket : Socket to modify
|
/// \param sock Handle of the socket to close
|
||||||
/// \param Block : New blocking state of the socket
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static void SetBlocking(SocketType Socket, bool Block);
|
static void close(SocketHandle sock);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set a socket as blocking or non-blocking
|
||||||
|
///
|
||||||
|
/// \param sock Handle of the socket
|
||||||
|
/// \param block New blocking state of the socket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static void setBlocking(SocketHandle sock, bool block);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the last socket error status
|
/// Get the last socket error status
|
||||||
|
@ -87,10 +98,12 @@ public :
|
||||||
/// \return Status corresponding to the last socket error
|
/// \return Status corresponding to the last socket error
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static Socket::Status GetErrorStatus();
|
static Socket::Status getErrorStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SOCKETHELPERUNIX_HPP
|
#endif // SFML_SOCKETIMPL_HPP
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -25,52 +25,62 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Network/SocketHelper.hpp>
|
#include <SFML/Network/Win32/SocketImpl.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Return the value of the invalid socket
|
sockaddr_in SocketImpl::createAddress(Uint32 address, unsigned short port)
|
||||||
|
{
|
||||||
|
sockaddr_in addr;
|
||||||
|
std::memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||||
|
addr.sin_addr.s_addr = htonl(address);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
SocketHelper::SocketType SocketHelper::InvalidSocket()
|
SocketHandle SocketImpl::invalidSocket()
|
||||||
{
|
{
|
||||||
return INVALID_SOCKET;
|
return INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Close / destroy a socket
|
void SocketImpl::close(SocketHandle sock)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
bool SocketHelper::Close(SocketHelper::SocketType Socket)
|
|
||||||
{
|
{
|
||||||
return closesocket(Socket) != -1;
|
closesocket(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set a socket as blocking or non-blocking
|
void SocketImpl::setBlocking(SocketHandle sock, bool block)
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block)
|
|
||||||
{
|
{
|
||||||
unsigned long Blocking = Block ? 0 : 1;
|
u_long blocking = block ? 0 : 1;
|
||||||
ioctlsocket(Socket, FIONBIO, &Blocking);
|
ioctlsocket(sock, FIONBIO, &blocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the last socket error status
|
Socket::Status SocketImpl::getErrorStatus()
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
Socket::Status SocketHelper::GetErrorStatus()
|
|
||||||
{
|
{
|
||||||
switch (WSAGetLastError())
|
switch (WSAGetLastError())
|
||||||
{
|
{
|
||||||
case WSAEWOULDBLOCK : return Socket::NotReady;
|
case WSAEWOULDBLOCK : return Socket::NotReady;
|
||||||
|
case WSAEALREADY : return Socket::NotReady;
|
||||||
case WSAECONNABORTED : return Socket::Disconnected;
|
case WSAECONNABORTED : return Socket::Disconnected;
|
||||||
case WSAECONNRESET : return Socket::Disconnected;
|
case WSAECONNRESET : return Socket::Disconnected;
|
||||||
case WSAETIMEDOUT : return Socket::Disconnected;
|
case WSAETIMEDOUT : return Socket::Disconnected;
|
||||||
case WSAENETRESET : return Socket::Disconnected;
|
case WSAENETRESET : return Socket::Disconnected;
|
||||||
case WSAENOTCONN : return Socket::Disconnected;
|
case WSAENOTCONN : return Socket::Disconnected;
|
||||||
|
case WSAEISCONN : return Socket::Done; // when connecting a non-blocking socket
|
||||||
default : return Socket::Error;
|
default : return Socket::Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,8 +95,8 @@ struct SocketInitializer
|
||||||
{
|
{
|
||||||
SocketInitializer()
|
SocketInitializer()
|
||||||
{
|
{
|
||||||
WSADATA InitData;
|
WSADATA init;
|
||||||
WSAStartup(MAKEWORD(2,2), &InitData);
|
WSAStartup(MAKEWORD(2, 2), &init);
|
||||||
}
|
}
|
||||||
|
|
||||||
~SocketInitializer()
|
~SocketInitializer()
|
||||||
|
@ -95,6 +105,8 @@ struct SocketInitializer
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketInitializer GlobalInitializer;
|
SocketInitializer globalInitializer;
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// SFML - Simple and Fast Multimedia Library
|
// SFML - Simple and Fast Multimedia Library
|
||||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied warranty.
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -22,58 +22,78 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef SFML_SOCKETHELPERWIN32_HPP
|
#ifndef SFML_SOCKETIMPL_HPP
|
||||||
#define SFML_SOCKETHELPERWIN32_HPP
|
#define SFML_SOCKETIMPL_HPP
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
#ifdef _WIN32_WINDOWS
|
||||||
|
#undef _WIN32_WINDOWS
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN32_WINNT
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
#endif
|
||||||
|
#define _WIN32_WINDOWS 0x0501
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// This class defines helper functions to do all the
|
/// \brief Helper class implementing all the non-portable
|
||||||
/// non-portable socket stuff. This class is meant for internal
|
/// socket stuff; this is the Windows version
|
||||||
/// use only
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
class SFML_API SocketHelper
|
class SocketImpl
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Define some socket types
|
// Types
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
typedef SOCKET SocketType;
|
typedef int AddrLength;
|
||||||
typedef int LengthType;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Return the value of the invalid socket
|
/// \brief Create an internal sockaddr_in address
|
||||||
///
|
///
|
||||||
/// \return Unique value of the invalid socket
|
/// \param address Target address
|
||||||
|
/// \param port Target port
|
||||||
|
///
|
||||||
|
/// \return sockaddr_in ready to be used by socket functions
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static SocketType InvalidSocket();
|
static sockaddr_in createAddress(Uint32 address, unsigned short port);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Close / destroy a socket
|
/// \brief Return the value of the invalid socket
|
||||||
///
|
///
|
||||||
/// \param Socket : Socket to close
|
/// \return Special value of the invalid socket
|
||||||
///
|
|
||||||
/// \return True on success
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static bool Close(SocketType Socket);
|
static SocketHandle invalidSocket();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Set a socket as blocking or non-blocking
|
/// \brief Close and destroy a socket
|
||||||
///
|
///
|
||||||
/// \param Socket : Socket to modify
|
/// \param sock Handle of the socket to close
|
||||||
/// \param Block : New blocking state of the socket
|
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static void SetBlocking(SocketType Socket, bool Block);
|
static void close(SocketHandle sock);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set a socket as blocking or non-blocking
|
||||||
|
///
|
||||||
|
/// \param sock Handle of the socket
|
||||||
|
/// \param block New blocking state of the socket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static void setBlocking(SocketHandle sock, bool block);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// Get the last socket error status
|
/// Get the last socket error status
|
||||||
|
@ -81,10 +101,12 @@ public :
|
||||||
/// \return Status corresponding to the last socket error
|
/// \return Status corresponding to the last socket error
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static Socket::Status GetErrorStatus();
|
static Socket::Status getErrorStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
#endif // SFML_SOCKETHELPERWIN32_HPP
|
#endif // SFML_SOCKETIMPL_HPP
|
|
@ -0,0 +1,110 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <streambuf>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// This class will be used as the default streambuf of sf::Err,
|
||||||
|
// it outputs to stderr by default (to keep the default behaviour)
|
||||||
|
class DefaultErrStreamBuf : public std::streambuf
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
DefaultErrStreamBuf()
|
||||||
|
{
|
||||||
|
// Allocate the write buffer
|
||||||
|
static const int size = 64;
|
||||||
|
char* buffer = new char[size];
|
||||||
|
setp(buffer, buffer + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DefaultErrStreamBuf()
|
||||||
|
{
|
||||||
|
// Synchronize
|
||||||
|
sync();
|
||||||
|
|
||||||
|
// Delete the write buffer
|
||||||
|
delete[] pbase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
virtual int overflow(int character)
|
||||||
|
{
|
||||||
|
if ((character != EOF) && (pptr() != epptr()))
|
||||||
|
{
|
||||||
|
// Valid character
|
||||||
|
return sputc(static_cast<char>(character));
|
||||||
|
}
|
||||||
|
else if (character != EOF)
|
||||||
|
{
|
||||||
|
// Not enough space in the buffer: synchronize output and try again
|
||||||
|
sync();
|
||||||
|
return overflow(character);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid character: synchronize output
|
||||||
|
return sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int sync()
|
||||||
|
{
|
||||||
|
// Check if there is something into the write buffer
|
||||||
|
if (pbase() != pptr())
|
||||||
|
{
|
||||||
|
// Print the contents of the write buffer into the standard error output
|
||||||
|
std::size_t size = static_cast<int>(pptr() - pbase());
|
||||||
|
fwrite(pbase(), 1, size, stderr);
|
||||||
|
|
||||||
|
// Reset the pointer position to the beginning of the write buffer
|
||||||
|
setp(pbase(), epptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::ostream& err()
|
||||||
|
{
|
||||||
|
static DefaultErrStreamBuf buffer;
|
||||||
|
static std::ostream stream(&buffer);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -0,0 +1,335 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/String.hpp>
|
||||||
|
#include <SFML/System/Utf.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
const std::size_t String::InvalidPos = std::basic_string<Uint32>::npos;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(char ansiChar, const std::locale& locale)
|
||||||
|
{
|
||||||
|
m_string += Utf32::decodeAnsi(ansiChar, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(wchar_t wideChar)
|
||||||
|
{
|
||||||
|
m_string += Utf32::decodeWide(wideChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(Uint32 utf32Char)
|
||||||
|
{
|
||||||
|
m_string += utf32Char;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const char* ansiString, const std::locale& locale)
|
||||||
|
{
|
||||||
|
if (ansiString)
|
||||||
|
{
|
||||||
|
std::size_t length = strlen(ansiString);
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
m_string.reserve(length + 1);
|
||||||
|
Utf32::fromAnsi(ansiString, ansiString + length, std::back_inserter(m_string), locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const std::string& ansiString, const std::locale& locale)
|
||||||
|
{
|
||||||
|
m_string.reserve(ansiString.length() + 1);
|
||||||
|
Utf32::fromAnsi(ansiString.begin(), ansiString.end(), std::back_inserter(m_string), locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const wchar_t* wideString)
|
||||||
|
{
|
||||||
|
if (wideString)
|
||||||
|
{
|
||||||
|
std::size_t length = std::wcslen(wideString);
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
m_string.reserve(length + 1);
|
||||||
|
Utf32::fromWide(wideString, wideString + length, std::back_inserter(m_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const std::wstring& wideString)
|
||||||
|
{
|
||||||
|
m_string.reserve(wideString.length() + 1);
|
||||||
|
Utf32::fromWide(wideString.begin(), wideString.end(), std::back_inserter(m_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const Uint32* utf32String)
|
||||||
|
{
|
||||||
|
if (utf32String)
|
||||||
|
m_string = utf32String;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const std::basic_string<Uint32>& utf32String) :
|
||||||
|
m_string(utf32String)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::String(const String& copy) :
|
||||||
|
m_string(copy.m_string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::operator std::string() const
|
||||||
|
{
|
||||||
|
return toAnsiString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::operator std::wstring() const
|
||||||
|
{
|
||||||
|
return toWideString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::string String::toAnsiString(const std::locale& locale) const
|
||||||
|
{
|
||||||
|
// Prepare the output string
|
||||||
|
std::string output;
|
||||||
|
output.reserve(m_string.length() + 1);
|
||||||
|
|
||||||
|
// Convert
|
||||||
|
Utf32::toAnsi(m_string.begin(), m_string.end(), std::back_inserter(output), 0, locale);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::wstring String::toWideString() const
|
||||||
|
{
|
||||||
|
// Prepare the output string
|
||||||
|
std::wstring output;
|
||||||
|
output.reserve(m_string.length() + 1);
|
||||||
|
|
||||||
|
// Convert
|
||||||
|
Utf32::toWide(m_string.begin(), m_string.end(), std::back_inserter(output), 0);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String& String::operator =(const String& right)
|
||||||
|
{
|
||||||
|
m_string = right.m_string;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String& String::operator +=(const String& right)
|
||||||
|
{
|
||||||
|
m_string += right.m_string;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Uint32 String::operator [](std::size_t index) const
|
||||||
|
{
|
||||||
|
return m_string[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Uint32& String::operator [](std::size_t index)
|
||||||
|
{
|
||||||
|
return m_string[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void String::clear()
|
||||||
|
{
|
||||||
|
m_string.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::size_t String::getSize() const
|
||||||
|
{
|
||||||
|
return m_string.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool String::isEmpty() const
|
||||||
|
{
|
||||||
|
return m_string.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void String::erase(std::size_t position, std::size_t count)
|
||||||
|
{
|
||||||
|
m_string.erase(position, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void String::insert(std::size_t position, const String& str)
|
||||||
|
{
|
||||||
|
m_string.insert(position, str.m_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::size_t String::find(const String& str, std::size_t start) const
|
||||||
|
{
|
||||||
|
return m_string.find(str.m_string, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
const Uint32* String::getData() const
|
||||||
|
{
|
||||||
|
return m_string.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::Iterator String::begin()
|
||||||
|
{
|
||||||
|
return m_string.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::ConstIterator String::begin() const
|
||||||
|
{
|
||||||
|
return m_string.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::Iterator String::end()
|
||||||
|
{
|
||||||
|
return m_string.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String::ConstIterator String::end() const
|
||||||
|
{
|
||||||
|
return m_string.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator ==(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
return left.m_string == right.m_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator !=(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator <(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
return left.m_string < right.m_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator >(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
return right < left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator <=(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
return !(right < left);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator >=(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
return !(left < right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String operator +(const String& left, const String& right)
|
||||||
|
{
|
||||||
|
String string = left;
|
||||||
|
string += right;
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -0,0 +1,239 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
const Time Time::Zero;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time::Time() :
|
||||||
|
m_microseconds(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
float Time::asSeconds() const
|
||||||
|
{
|
||||||
|
return m_microseconds / 1000000.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Int32 Time::asMilliseconds() const
|
||||||
|
{
|
||||||
|
return static_cast<Int32>(m_microseconds / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Int64 Time::asMicroseconds() const
|
||||||
|
{
|
||||||
|
return m_microseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time::Time(Int64 microseconds) :
|
||||||
|
m_microseconds(microseconds)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time seconds(float amount)
|
||||||
|
{
|
||||||
|
return Time(static_cast<Int64>(amount * 1000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time milliseconds(Int32 amount)
|
||||||
|
{
|
||||||
|
return Time(static_cast<Int64>(amount) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time microseconds(Int64 amount)
|
||||||
|
{
|
||||||
|
return Time(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator ==(Time left, Time right)
|
||||||
|
{
|
||||||
|
return left.asMicroseconds() == right.asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator !=(Time left, Time right)
|
||||||
|
{
|
||||||
|
return left.asMicroseconds() != right.asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator <(Time left, Time right)
|
||||||
|
{
|
||||||
|
return left.asMicroseconds() < right.asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator >(Time left, Time right)
|
||||||
|
{
|
||||||
|
return left.asMicroseconds() > right.asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator <=(Time left, Time right)
|
||||||
|
{
|
||||||
|
return left.asMicroseconds() <= right.asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool operator >=(Time left, Time right)
|
||||||
|
{
|
||||||
|
return left.asMicroseconds() >= right.asMicroseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator -(Time right)
|
||||||
|
{
|
||||||
|
return microseconds(-right.asMicroseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator +(Time left, Time right)
|
||||||
|
{
|
||||||
|
return microseconds(left.asMicroseconds() + right.asMicroseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time& operator +=(Time& left, Time right)
|
||||||
|
{
|
||||||
|
return left = left + right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator -(Time left, Time right)
|
||||||
|
{
|
||||||
|
return microseconds(left.asMicroseconds() - right.asMicroseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time& operator -=(Time& left, Time right)
|
||||||
|
{
|
||||||
|
return left = left - right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator *(Time left, float right)
|
||||||
|
{
|
||||||
|
return seconds(left.asSeconds() * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator *(Time left, Int64 right)
|
||||||
|
{
|
||||||
|
return microseconds(left.asMicroseconds() * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator *(float left, Time right)
|
||||||
|
{
|
||||||
|
return right * left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator *(Int64 left, Time right)
|
||||||
|
{
|
||||||
|
return right * left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time& operator *=(Time& left, float right)
|
||||||
|
{
|
||||||
|
return left = left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time& operator *=(Time& left, Int64 right)
|
||||||
|
{
|
||||||
|
return left = left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator /(Time left, float right)
|
||||||
|
{
|
||||||
|
return seconds(left.asSeconds() / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time operator /(Time left, Int64 right)
|
||||||
|
{
|
||||||
|
return microseconds(left.asMicroseconds() / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time& operator /=(Time& left, float right)
|
||||||
|
{
|
||||||
|
return left = left / right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time& operator /=(Time& left, Int64 right)
|
||||||
|
{
|
||||||
|
return left = left / right;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
|
@ -238,6 +238,7 @@ set(LIBS
|
||||||
inputcommon
|
inputcommon
|
||||||
${LZO}
|
${LZO}
|
||||||
sfml-network
|
sfml-network
|
||||||
|
sfml-system
|
||||||
videoogl
|
videoogl
|
||||||
videosoftware
|
videosoftware
|
||||||
z
|
z
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under GPLv2
|
// Licensed under GPLv2
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/StdMakeUnique.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/HW/EXI_Device.h"
|
#include "Core/HW/EXI_Device.h"
|
||||||
#include "Core/HW/EXI_DeviceGecko.h"
|
#include "Core/HW/EXI_DeviceGecko.h"
|
||||||
|
@ -10,8 +11,8 @@ u16 GeckoSockServer::server_port;
|
||||||
int GeckoSockServer::client_count;
|
int GeckoSockServer::client_count;
|
||||||
std::thread GeckoSockServer::connectionThread;
|
std::thread GeckoSockServer::connectionThread;
|
||||||
volatile bool GeckoSockServer::server_running;
|
volatile bool GeckoSockServer::server_running;
|
||||||
std::queue<sf::SocketTCP> GeckoSockServer::waiting_socks;
|
|
||||||
std::mutex GeckoSockServer::connection_lock;
|
std::mutex GeckoSockServer::connection_lock;
|
||||||
|
std::queue<std::unique_ptr<sf::TcpSocket>> GeckoSockServer::waiting_socks;
|
||||||
|
|
||||||
GeckoSockServer::GeckoSockServer()
|
GeckoSockServer::GeckoSockServer()
|
||||||
: client_running(false)
|
: client_running(false)
|
||||||
|
@ -41,11 +42,12 @@ void GeckoSockServer::GeckoConnectionWaiter()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("Gecko Connection Waiter");
|
Common::SetCurrentThreadName("Gecko Connection Waiter");
|
||||||
|
|
||||||
sf::SocketTCP server;
|
sf::TcpListener server;
|
||||||
server_port = 0xd6ec; // "dolphin gecko"
|
server_port = 0xd6ec; // "dolphin gecko"
|
||||||
for (int bind_tries = 0; bind_tries <= 10 && !server_running; bind_tries++)
|
for (int bind_tries = 0; bind_tries <= 10 && !server_running; bind_tries++)
|
||||||
{
|
{
|
||||||
if (!(server_running = server.Listen(server_port)))
|
server_running = server.listen(server_port) == sf::Socket::Done;
|
||||||
|
if (!server_running)
|
||||||
server_port++;
|
server_port++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,22 +58,23 @@ void GeckoSockServer::GeckoConnectionWaiter()
|
||||||
StringFromFormat("USBGecko: Listening on TCP port %u", server_port),
|
StringFromFormat("USBGecko: Listening on TCP port %u", server_port),
|
||||||
5000);
|
5000);
|
||||||
|
|
||||||
server.SetBlocking(false);
|
server.setBlocking(false);
|
||||||
|
|
||||||
sf::SocketTCP new_client;
|
auto new_client = std::make_unique<sf::TcpSocket>();
|
||||||
while (server_running)
|
while (server_running)
|
||||||
{
|
{
|
||||||
if (server.Accept(new_client) == sf::Socket::Done)
|
if (server.accept(*new_client) == sf::Socket::Done)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(connection_lock);
|
std::lock_guard<std::mutex> lk(connection_lock);
|
||||||
waiting_socks.push(new_client);
|
waiting_socks.push(std::move(new_client));
|
||||||
|
|
||||||
|
new_client = std::make_unique<sf::TcpSocket>();
|
||||||
}
|
}
|
||||||
SLEEP(1);
|
SLEEP(1);
|
||||||
}
|
}
|
||||||
server.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeckoSockServer::GetAvailableSock(sf::SocketTCP &sock_to_fill)
|
bool GeckoSockServer::GetAvailableSock()
|
||||||
{
|
{
|
||||||
bool sock_filled = false;
|
bool sock_filled = false;
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ bool GeckoSockServer::GetAvailableSock(sf::SocketTCP &sock_to_fill)
|
||||||
|
|
||||||
if (!waiting_socks.empty())
|
if (!waiting_socks.empty())
|
||||||
{
|
{
|
||||||
sock_to_fill = waiting_socks.front();
|
client = std::move(waiting_socks.front());
|
||||||
if (clientThread.joinable())
|
if (clientThread.joinable())
|
||||||
{
|
{
|
||||||
client_running = false;
|
client_running = false;
|
||||||
|
@ -103,7 +106,7 @@ void GeckoSockServer::ClientThread()
|
||||||
|
|
||||||
Common::SetCurrentThreadName("Gecko Client");
|
Common::SetCurrentThreadName("Gecko Client");
|
||||||
|
|
||||||
client.SetBlocking(false);
|
client->setBlocking(false);
|
||||||
|
|
||||||
while (client_running)
|
while (client_running)
|
||||||
{
|
{
|
||||||
|
@ -116,7 +119,7 @@ void GeckoSockServer::ClientThread()
|
||||||
char data[128];
|
char data[128];
|
||||||
std::size_t got = 0;
|
std::size_t got = 0;
|
||||||
|
|
||||||
if (client.Receive(&data[0], ArraySize(data), got) == sf::Socket::Disconnected)
|
if (client->receive(&data[0], ArraySize(data), got) == sf::Socket::Disconnected)
|
||||||
client_running = false;
|
client_running = false;
|
||||||
|
|
||||||
if (got != 0)
|
if (got != 0)
|
||||||
|
@ -133,7 +136,7 @@ void GeckoSockServer::ClientThread()
|
||||||
std::vector<char> packet(send_fifo.begin(), send_fifo.end());
|
std::vector<char> packet(send_fifo.begin(), send_fifo.end());
|
||||||
send_fifo.clear();
|
send_fifo.clear();
|
||||||
|
|
||||||
if (client.Send(&packet[0], packet.size()) == sf::Socket::Disconnected)
|
if (client->send(&packet[0], packet.size()) == sf::Socket::Disconnected)
|
||||||
client_running = false;
|
client_running = false;
|
||||||
}
|
}
|
||||||
} // unlock transfer
|
} // unlock transfer
|
||||||
|
@ -142,7 +145,7 @@ void GeckoSockServer::ClientThread()
|
||||||
Common::YieldCPU();
|
Common::YieldCPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
client.Close();
|
client->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
|
void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
|
||||||
|
@ -150,8 +153,8 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
|
||||||
// We don't really care about _uSize
|
// We don't really care about _uSize
|
||||||
(void)_uSize;
|
(void)_uSize;
|
||||||
|
|
||||||
if (!client.IsValid())
|
if (!client || client->getLocalPort() == 0)
|
||||||
GetAvailableSock(client);
|
GetAvailableSock();
|
||||||
|
|
||||||
switch (_uData >> 28)
|
switch (_uData >> 28)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,15 +14,14 @@
|
||||||
#include "Core/HW/EXI_Device.h"
|
#include "Core/HW/EXI_Device.h"
|
||||||
|
|
||||||
class GeckoSockServer
|
class GeckoSockServer
|
||||||
: public sf::SocketTCP
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GeckoSockServer();
|
GeckoSockServer();
|
||||||
~GeckoSockServer();
|
~GeckoSockServer();
|
||||||
bool GetAvailableSock(sf::SocketTCP &sock_to_fill);
|
bool GetAvailableSock();
|
||||||
|
|
||||||
// Client for this server object
|
// Client for this server object
|
||||||
sf::SocketTCP client;
|
std::unique_ptr<sf::TcpSocket> client;
|
||||||
void ClientThread();
|
void ClientThread();
|
||||||
std::thread clientThread;
|
std::thread clientThread;
|
||||||
std::mutex transfer_lock;
|
std::mutex transfer_lock;
|
||||||
|
@ -40,8 +39,8 @@ private:
|
||||||
static u16 server_port;
|
static u16 server_port;
|
||||||
static volatile bool server_running;
|
static volatile bool server_running;
|
||||||
static std::thread connectionThread;
|
static std::thread connectionThread;
|
||||||
static std::queue<sf::SocketTCP> waiting_socks;
|
|
||||||
static std::mutex connection_lock;
|
static std::mutex connection_lock;
|
||||||
|
static std::queue<std::unique_ptr<sf::TcpSocket>> waiting_socks;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEXIGecko
|
class CEXIGecko
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "Common/CommonFuncs.h"
|
#include "Common/CommonFuncs.h"
|
||||||
|
#include "Common/StdMakeUnique.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/HW/SI_Device.h"
|
#include "Core/HW/SI_Device.h"
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
#include "SFML/Network.hpp"
|
#include "SFML/Network.hpp"
|
||||||
|
|
||||||
static std::thread connectionThread;
|
static std::thread connectionThread;
|
||||||
static std::queue<sf::SocketTCP> waiting_socks;
|
static std::queue<std::unique_ptr<sf::TcpSocket>> waiting_socks;
|
||||||
static std::mutex cs_gba;
|
static std::mutex cs_gba;
|
||||||
namespace { volatile bool server_running; }
|
namespace { volatile bool server_running; }
|
||||||
|
|
||||||
|
@ -25,25 +26,25 @@ static void GBAConnectionWaiter()
|
||||||
|
|
||||||
Common::SetCurrentThreadName("GBA Connection Waiter");
|
Common::SetCurrentThreadName("GBA Connection Waiter");
|
||||||
|
|
||||||
sf::SocketTCP server;
|
sf::TcpListener server;
|
||||||
// "dolphin gba"
|
// "dolphin gba"
|
||||||
if (!server.Listen(0xd6ba))
|
if (server.listen(0xd6ba) != sf::Socket::Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
server.SetBlocking(false);
|
server.setBlocking(false);
|
||||||
|
|
||||||
sf::SocketTCP new_client;
|
auto new_client = std::make_unique<sf::TcpSocket>();
|
||||||
while (server_running)
|
while (server_running)
|
||||||
{
|
{
|
||||||
if (server.Accept(new_client) == sf::Socket::Done)
|
if (server.accept(*new_client) == sf::Socket::Done)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(cs_gba);
|
std::lock_guard<std::mutex> lk(cs_gba);
|
||||||
waiting_socks.push(new_client);
|
waiting_socks.push(std::move(new_client));
|
||||||
|
|
||||||
|
new_client = std::make_unique<sf::TcpSocket>();
|
||||||
}
|
}
|
||||||
SLEEP(1);
|
SLEEP(1);
|
||||||
}
|
}
|
||||||
server.Close();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAConnectionWaiter_Shutdown()
|
void GBAConnectionWaiter_Shutdown()
|
||||||
|
@ -53,7 +54,7 @@ void GBAConnectionWaiter_Shutdown()
|
||||||
connectionThread.join();
|
connectionThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetAvailableSock(sf::SocketTCP& sock_to_fill)
|
static bool GetAvailableSock(std::unique_ptr<sf::TcpSocket>& sock_to_fill)
|
||||||
{
|
{
|
||||||
bool sock_filled = false;
|
bool sock_filled = false;
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ static bool GetAvailableSock(sf::SocketTCP& sock_to_fill)
|
||||||
|
|
||||||
if (!waiting_socks.empty())
|
if (!waiting_socks.empty())
|
||||||
{
|
{
|
||||||
sock_to_fill = waiting_socks.front();
|
sock_to_fill = std::move(waiting_socks.front());
|
||||||
waiting_socks.pop();
|
waiting_socks.pop();
|
||||||
sock_filled = true;
|
sock_filled = true;
|
||||||
}
|
}
|
||||||
|
@ -77,13 +78,12 @@ GBASockServer::GBASockServer()
|
||||||
|
|
||||||
GBASockServer::~GBASockServer()
|
GBASockServer::~GBASockServer()
|
||||||
{
|
{
|
||||||
client.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocking, since GBA must always send lower byte of REG_JOYSTAT
|
// Blocking, since GBA must always send lower byte of REG_JOYSTAT
|
||||||
void GBASockServer::Transfer(char* si_buffer)
|
void GBASockServer::Transfer(char* si_buffer)
|
||||||
{
|
{
|
||||||
if (!client.IsValid())
|
if (!client || client->getLocalPort() == 0)
|
||||||
if (!GetAvailableSock(client))
|
if (!GetAvailableSock(client))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -93,9 +93,9 @@ void GBASockServer::Transfer(char* si_buffer)
|
||||||
u8 cmd = *current_data;
|
u8 cmd = *current_data;
|
||||||
|
|
||||||
if (cmd == CMD_WRITE)
|
if (cmd == CMD_WRITE)
|
||||||
client.Send(current_data, sizeof(current_data));
|
client->send(current_data, sizeof(current_data));
|
||||||
else
|
else
|
||||||
client.Send(current_data, 1);
|
client->send(current_data, 1);
|
||||||
|
|
||||||
DEBUG_LOG(SERIALINTERFACE, "> command %02x %02x%02x%02x%02x",
|
DEBUG_LOG(SERIALINTERFACE, "> command %02x %02x%02x%02x%02x",
|
||||||
(u8)current_data[0], (u8)current_data[1], (u8)current_data[2],
|
(u8)current_data[0], (u8)current_data[1], (u8)current_data[2],
|
||||||
|
@ -103,8 +103,8 @@ void GBASockServer::Transfer(char* si_buffer)
|
||||||
|
|
||||||
memset(current_data, 0, sizeof(current_data));
|
memset(current_data, 0, sizeof(current_data));
|
||||||
size_t num_received = 0;
|
size_t num_received = 0;
|
||||||
if (client.Receive(current_data, sizeof(current_data), num_received) == sf::Socket::Disconnected)
|
if (client->receive(current_data, sizeof(current_data), num_received) == sf::Socket::Disconnected)
|
||||||
client.Close();
|
client->disconnect();
|
||||||
|
|
||||||
DEBUG_LOG(SERIALINTERFACE, "< %02x%02x%02x%02x%02x",
|
DEBUG_LOG(SERIALINTERFACE, "< %02x%02x%02x%02x%02x",
|
||||||
(u8)current_data[0], (u8)current_data[1], (u8)current_data[2],
|
(u8)current_data[0], (u8)current_data[1], (u8)current_data[2],
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
void GBAConnectionWaiter_Shutdown();
|
void GBAConnectionWaiter_Shutdown();
|
||||||
|
|
||||||
class GBASockServer : public sf::SocketTCP
|
class GBASockServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GBASockServer();
|
GBASockServer();
|
||||||
|
@ -29,7 +29,7 @@ private:
|
||||||
CMD_WRITE = 0x15
|
CMD_WRITE = 0x15
|
||||||
};
|
};
|
||||||
|
|
||||||
sf::SocketTCP client;
|
std::unique_ptr<sf::TcpSocket> client;
|
||||||
char current_data[5];
|
char current_data[5];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -204,10 +204,10 @@ bool Wiimote::Read()
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 &&
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 &&
|
||||||
index == WIIMOTE_BALANCE_BOARD)
|
index == WIIMOTE_BALANCE_BOARD)
|
||||||
{
|
{
|
||||||
static sf::SocketUDP Socket;
|
static sf::UdpSocket Socket;
|
||||||
Socket.Send((char*)rpt.data(),
|
Socket.send((char*)rpt.data(),
|
||||||
rpt.size(),
|
rpt.size(),
|
||||||
sf::IPAddress::LocalHost,
|
sf::IpAddress::LocalHost,
|
||||||
SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort);
|
SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,8 +237,8 @@ bool Wiimote::Write()
|
||||||
{
|
{
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 && index == WIIMOTE_BALANCE_BOARD)
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 && index == WIIMOTE_BALANCE_BOARD)
|
||||||
{
|
{
|
||||||
static sf::SocketUDP Socket;
|
static sf::UdpSocket Socket;
|
||||||
Socket.Send((char*)rpt.data(), rpt.size(), sf::IPAddress::LocalHost, SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort);
|
Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost, SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort);
|
||||||
}
|
}
|
||||||
IOWrite(rpt.data(), rpt.size());
|
IOWrite(rpt.data(), rpt.size());
|
||||||
|
|
||||||
|
|
|
@ -43,18 +43,18 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
|
|
||||||
is_connected = false;
|
is_connected = false;
|
||||||
|
|
||||||
if (m_socket.Connect(port, address, 5) == sf::Socket::Done)
|
if (m_socket.connect(address, port, sf::seconds(5)) == sf::Socket::Done)
|
||||||
{
|
{
|
||||||
// send connect message
|
// send connect message
|
||||||
sf::Packet spac;
|
sf::Packet spac;
|
||||||
spac << NETPLAY_VERSION;
|
spac << NETPLAY_VERSION;
|
||||||
spac << netplay_dolphin_ver;
|
spac << netplay_dolphin_ver;
|
||||||
spac << name;
|
spac << name;
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
|
|
||||||
sf::Packet rpac;
|
sf::Packet rpac;
|
||||||
// TODO: make this not hang
|
// TODO: make this not hang
|
||||||
m_socket.Receive(rpac);
|
m_socket.receive(rpac);
|
||||||
MessageId error;
|
MessageId error;
|
||||||
rpac >> error;
|
rpac >> error;
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
PanicAlertT("The server sent an unknown error message!");
|
PanicAlertT("The server sent an unknown error message!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_socket.Close();
|
m_socket.disconnect();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -96,7 +96,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
//PanicAlertT("Connection successful: assigned player id: %d", m_pid);
|
//PanicAlertT("Connection successful: assigned player id: %d", m_pid);
|
||||||
is_connected = true;
|
is_connected = true;
|
||||||
|
|
||||||
m_selector.Add(m_socket);
|
m_selector.add(m_socket);
|
||||||
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||||
spac << ping_key;
|
spac << ping_key;
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -319,10 +319,10 @@ void NetPlayClient::ThreadFunc()
|
||||||
{
|
{
|
||||||
while (m_do_loop)
|
while (m_do_loop)
|
||||||
{
|
{
|
||||||
if (m_selector.Wait(0.01f))
|
if (m_selector.wait(sf::milliseconds(10)))
|
||||||
{
|
{
|
||||||
sf::Packet rpac;
|
sf::Packet rpac;
|
||||||
switch (m_socket.Receive(rpac))
|
switch (m_socket.receive(rpac))
|
||||||
{
|
{
|
||||||
case sf::Socket::Done :
|
case sf::Socket::Done :
|
||||||
OnData(rpac);
|
OnData(rpac);
|
||||||
|
@ -340,7 +340,7 @@ void NetPlayClient::ThreadFunc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_socket.Close();
|
m_socket.disconnect();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ void NetPlayClient::SendChatMessage(const std::string& msg)
|
||||||
spac << msg;
|
spac << msg;
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---CPU--- thread
|
// called from ---CPU--- thread
|
||||||
|
@ -416,7 +416,7 @@ void NetPlayClient::SendPadState(const PadMapping in_game_pad, const GCPadStatus
|
||||||
spac << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight;
|
spac << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight;
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---CPU--- thread
|
// called from ---CPU--- thread
|
||||||
|
@ -433,7 +433,7 @@ void NetPlayClient::SendWiimoteState(const PadMapping in_game_pad, const NetWiim
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---GUI--- thread
|
// called from ---GUI--- thread
|
||||||
|
@ -448,7 +448,7 @@ bool NetPlayClient::StartGame(const std::string &path)
|
||||||
spac << (char *)&g_NetPlaySettings;
|
spac << (char *)&g_NetPlaySettings;
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
|
|
||||||
if (m_is_running)
|
if (m_is_running)
|
||||||
{
|
{
|
||||||
|
@ -751,7 +751,7 @@ void NetPlayClient::Stop()
|
||||||
{
|
{
|
||||||
sf::Packet spac;
|
sf::Packet spac;
|
||||||
spac << (MessageId)NP_MSG_STOP_GAME;
|
spac << (MessageId)NP_MSG_STOP_GAME;
|
||||||
m_socket.Send(spac);
|
m_socket.send(spac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,9 +87,9 @@ protected:
|
||||||
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];
|
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];
|
||||||
|
|
||||||
NetPlayUI* m_dialog;
|
NetPlayUI* m_dialog;
|
||||||
sf::SocketTCP m_socket;
|
sf::TcpSocket m_socket;
|
||||||
std::thread m_thread;
|
std::thread m_thread;
|
||||||
sf::Selector<sf::SocketTCP> m_selector;
|
sf::SocketSelector m_selector;
|
||||||
|
|
||||||
std::string m_selected_game;
|
std::string m_selected_game;
|
||||||
volatile bool m_is_running;
|
volatile bool m_is_running;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/StdMakeUnique.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Core/NetPlayServer.h"
|
#include "Core/NetPlayServer.h"
|
||||||
#include "InputCommon/GCPadStatus.h"
|
#include "InputCommon/GCPadStatus.h"
|
||||||
|
@ -15,7 +16,7 @@ NetPlayServer::~NetPlayServer()
|
||||||
{
|
{
|
||||||
m_do_loop = false;
|
m_do_loop = false;
|
||||||
m_thread.join();
|
m_thread.join();
|
||||||
m_socket.Close();
|
m_socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
|
@ -31,11 +32,11 @@ NetPlayServer::NetPlayServer(const u16 port) : is_connected(false), m_is_running
|
||||||
{
|
{
|
||||||
memset(m_pad_map, -1, sizeof(m_pad_map));
|
memset(m_pad_map, -1, sizeof(m_pad_map));
|
||||||
memset(m_wiimote_map, -1, sizeof(m_wiimote_map));
|
memset(m_wiimote_map, -1, sizeof(m_wiimote_map));
|
||||||
if (m_socket.Listen(port))
|
if (m_socket.listen(port) == sf::Socket::Done)
|
||||||
{
|
{
|
||||||
is_connected = true;
|
is_connected = true;
|
||||||
m_do_loop = true;
|
m_do_loop = true;
|
||||||
m_selector.Add(m_socket);
|
m_selector.add(m_socket);
|
||||||
m_thread = std::thread(&NetPlayServer::ThreadFunc, this);
|
m_thread = std::thread(&NetPlayServer::ThreadFunc, this);
|
||||||
m_target_buffer_size = 5;
|
m_target_buffer_size = 5;
|
||||||
}
|
}
|
||||||
|
@ -64,17 +65,14 @@ void NetPlayServer::ThreadFunc()
|
||||||
m_update_pings = false;
|
m_update_pings = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check which sockets need attention
|
// check if any sockets need attention
|
||||||
const unsigned int num = m_selector.Wait(0.01f);
|
if (m_selector.wait(sf::milliseconds(10)))
|
||||||
for (unsigned int i=0; i<num; ++i)
|
|
||||||
{
|
{
|
||||||
sf::SocketTCP ready_socket = m_selector.GetSocketReady(i);
|
|
||||||
|
|
||||||
// listening socket
|
// listening socket
|
||||||
if (ready_socket == m_socket)
|
if (m_selector.isReady(m_socket))
|
||||||
{
|
{
|
||||||
sf::SocketTCP accept_socket;
|
auto accept_socket = std::make_unique<sf::TcpSocket>();
|
||||||
m_socket.Accept(accept_socket);
|
m_socket.accept(*accept_socket);
|
||||||
|
|
||||||
unsigned int error;
|
unsigned int error;
|
||||||
{
|
{
|
||||||
|
@ -87,46 +85,51 @@ void NetPlayServer::ThreadFunc()
|
||||||
sf::Packet spac;
|
sf::Packet spac;
|
||||||
spac << (MessageId)error;
|
spac << (MessageId)error;
|
||||||
// don't need to lock, this client isn't in the client map
|
// don't need to lock, this client isn't in the client map
|
||||||
accept_socket.Send(spac);
|
accept_socket->send(spac);
|
||||||
|
accept_socket->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// client sockets
|
||||||
|
for (auto it = m_players.begin(); it != m_players.end();)
|
||||||
|
{
|
||||||
|
// move iterator on immediately so client can be removed
|
||||||
|
Client& client = *it;
|
||||||
|
it++;
|
||||||
|
|
||||||
// TODO: not sure if client gets the message if i close right away
|
if (m_selector.isReady(*client.socket))
|
||||||
accept_socket.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// client socket
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
sf::Packet rpac;
|
sf::Packet rpac;
|
||||||
switch (ready_socket.Receive(rpac))
|
switch (client.socket->receive(rpac))
|
||||||
{
|
{
|
||||||
case sf::Socket::Done :
|
case sf::Socket::Done :
|
||||||
// if a bad packet is received, disconnect the client
|
// if a bad packet is received, disconnect the client
|
||||||
if (0 == OnData(rpac, ready_socket))
|
if (0 == OnData(rpac, client))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//case sf::Socket::Disconnected :
|
//case sf::Socket::Disconnected :
|
||||||
default :
|
default :
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
|
||||||
OnDisconnect(ready_socket);
|
OnDisconnect(client);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// close listening socket and client sockets
|
// close listening socket and client sockets
|
||||||
for (auto& player_entry : m_players)
|
for (auto& player_entry : m_players)
|
||||||
player_entry.second.socket.Close();
|
player_entry.socket->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---NETPLAY--- thread
|
// called from ---NETPLAY--- thread
|
||||||
unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
|
unsigned int NetPlayServer::OnConnect(std::unique_ptr<sf::TcpSocket>& socket)
|
||||||
{
|
{
|
||||||
sf::Packet rpac;
|
sf::Packet rpac;
|
||||||
// TODO: make this not hang / check if good packet
|
// TODO: make this not hang / check if good packet
|
||||||
socket.Receive(rpac);
|
socket->receive(rpac);
|
||||||
|
|
||||||
std::string npver;
|
std::string npver;
|
||||||
rpac >> npver;
|
rpac >> npver;
|
||||||
|
@ -146,7 +149,7 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
|
||||||
m_update_pings = true;
|
m_update_pings = true;
|
||||||
|
|
||||||
Client player;
|
Client player;
|
||||||
player.socket = socket;
|
player.socket = std::move(socket);
|
||||||
rpac >> player.revision;
|
rpac >> player.revision;
|
||||||
rpac >> player.name;
|
rpac >> player.name;
|
||||||
|
|
||||||
|
@ -154,7 +157,7 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
|
||||||
PlayerId pid = 1;
|
PlayerId pid = 1;
|
||||||
for (auto i = m_players.begin(); i != m_players.end(); ++i)
|
for (auto i = m_players.begin(); i != m_players.end(); ++i)
|
||||||
{
|
{
|
||||||
if (i->second.pid == pid)
|
if (i->pid == pid)
|
||||||
{
|
{
|
||||||
pid++;
|
pid++;
|
||||||
i = m_players.begin();
|
i = m_players.begin();
|
||||||
|
@ -182,57 +185,56 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
|
||||||
SendToClients(spac);
|
SendToClients(spac);
|
||||||
|
|
||||||
// send new client success message with their id
|
// send new client success message with their id
|
||||||
spac.Clear();
|
spac.clear();
|
||||||
spac << (MessageId)0;
|
spac << (MessageId)0;
|
||||||
spac << player.pid;
|
spac << player.pid;
|
||||||
socket.Send(spac);
|
player.socket->send(spac);
|
||||||
|
|
||||||
// send new client the selected game
|
// send new client the selected game
|
||||||
if (m_selected_game != "")
|
if (m_selected_game != "")
|
||||||
{
|
{
|
||||||
spac.Clear();
|
spac.clear();
|
||||||
spac << (MessageId)NP_MSG_CHANGE_GAME;
|
spac << (MessageId)NP_MSG_CHANGE_GAME;
|
||||||
spac << m_selected_game;
|
spac << m_selected_game;
|
||||||
socket.Send(spac);
|
player.socket->send(spac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send the pad buffer value
|
// send the pad buffer value
|
||||||
spac.Clear();
|
spac.clear();
|
||||||
spac << (MessageId)NP_MSG_PAD_BUFFER;
|
spac << (MessageId)NP_MSG_PAD_BUFFER;
|
||||||
spac << (u32)m_target_buffer_size;
|
spac << (u32)m_target_buffer_size;
|
||||||
socket.Send(spac);
|
player.socket->send(spac);
|
||||||
|
|
||||||
// sync values with new client
|
// sync values with new client
|
||||||
for (const auto& p : m_players)
|
for (const auto& p : m_players)
|
||||||
{
|
{
|
||||||
spac.Clear();
|
spac.clear();
|
||||||
spac << (MessageId)NP_MSG_PLAYER_JOIN;
|
spac << (MessageId)NP_MSG_PLAYER_JOIN;
|
||||||
spac << p.second.pid << p.second.name << p.second.revision;
|
spac << p.pid << p.name << p.revision;
|
||||||
socket.Send(spac);
|
player.socket->send(spac);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // unlock send
|
} // unlock send
|
||||||
|
|
||||||
|
// add client to selector/ used for receiving
|
||||||
|
m_selector.add(*player.socket);
|
||||||
|
|
||||||
// add client to the player list
|
// add client to the player list
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
|
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
|
||||||
m_players[socket] = player;
|
m_players.push_back(std::move(player));
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
UpdatePadMapping(); // sync pad mappings with everyone
|
UpdatePadMapping(); // sync pad mappings with everyone
|
||||||
UpdateWiimoteMapping();
|
UpdateWiimoteMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// add client to selector/ used for receiving
|
|
||||||
m_selector.Add(socket);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---NETPLAY--- thread
|
// called from ---NETPLAY--- thread
|
||||||
unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket)
|
unsigned int NetPlayServer::OnDisconnect(Client& player)
|
||||||
{
|
{
|
||||||
PlayerId pid = m_players[socket].pid;
|
PlayerId pid = player.pid;
|
||||||
|
|
||||||
if (m_is_running)
|
if (m_is_running)
|
||||||
{
|
{
|
||||||
|
@ -258,10 +260,10 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket)
|
||||||
spac << (MessageId)NP_MSG_PLAYER_LEAVE;
|
spac << (MessageId)NP_MSG_PLAYER_LEAVE;
|
||||||
spac << pid;
|
spac << pid;
|
||||||
|
|
||||||
m_selector.Remove(socket);
|
m_selector.remove(*player.socket);
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
|
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
|
||||||
m_players.erase(m_players.find(socket));
|
m_players.remove(player);
|
||||||
|
|
||||||
// alert other players of disconnect
|
// alert other players of disconnect
|
||||||
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
|
||||||
|
@ -359,14 +361,13 @@ void NetPlayServer::AdjustPadBufferSize(unsigned int size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---NETPLAY--- thread
|
// called from ---NETPLAY--- thread
|
||||||
unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
|
unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
||||||
{
|
{
|
||||||
MessageId mid;
|
MessageId mid;
|
||||||
packet >> mid;
|
packet >> mid;
|
||||||
|
|
||||||
// don't need lock because this is the only thread that modifies the players
|
// don't need lock because this is the only thread that modifies the players
|
||||||
// only need locks for writes to m_players in this thread
|
// only need locks for writes to m_players in this thread
|
||||||
Client& player = m_players[socket];
|
|
||||||
|
|
||||||
switch (mid)
|
switch (mid)
|
||||||
{
|
{
|
||||||
|
@ -568,12 +569,11 @@ bool NetPlayServer::StartGame()
|
||||||
// called from multiple threads
|
// called from multiple threads
|
||||||
void NetPlayServer::SendToClients(sf::Packet& packet, const PlayerId skip_pid)
|
void NetPlayServer::SendToClients(sf::Packet& packet, const PlayerId skip_pid)
|
||||||
{
|
{
|
||||||
for (std::pair<const sf::SocketTCP, Client>& p : m_players)
|
for (auto& p : m_players)
|
||||||
{
|
{
|
||||||
if (p.second.pid &&
|
if (p.pid && p.pid != skip_pid)
|
||||||
p.second.pid != skip_pid)
|
|
||||||
{
|
{
|
||||||
p.second.socket.Send(packet);
|
p.socket->send(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -582,9 +582,9 @@ void NetPlayServer::KickPlayer(u8 player)
|
||||||
{
|
{
|
||||||
for (auto& current_player : m_players)
|
for (auto& current_player : m_players)
|
||||||
{
|
{
|
||||||
if (current_player.second.pid == player)
|
if (current_player.pid == player)
|
||||||
{
|
{
|
||||||
current_player.second.socket.Close();
|
current_player.socket->disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,7 +613,7 @@ void NetPlayServer::TryPortmapping(u16 port)
|
||||||
// UPnP thread: try to map a port
|
// UPnP thread: try to map a port
|
||||||
void NetPlayServer::mapPortThread(const u16 port)
|
void NetPlayServer::mapPortThread(const u16 port)
|
||||||
{
|
{
|
||||||
std::string ourIP = sf::IPAddress::GetLocalAddress().ToString();
|
std::string ourIP = sf::IpAddress::getLocalAddress().toString();
|
||||||
|
|
||||||
if (!m_upnp_inited)
|
if (!m_upnp_inited)
|
||||||
if (!initUPnP())
|
if (!initUPnP())
|
||||||
|
|
|
@ -56,15 +56,30 @@ private:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string revision;
|
std::string revision;
|
||||||
|
|
||||||
sf::SocketTCP socket;
|
std::unique_ptr<sf::TcpSocket> socket;
|
||||||
u32 ping;
|
u32 ping;
|
||||||
u32 current_game;
|
u32 current_game;
|
||||||
|
|
||||||
|
// VS2013 does not generate the right constructors here automatically
|
||||||
|
// like GCC does, so we implement them manually
|
||||||
|
Client() = default;
|
||||||
|
Client(const Client& other) = delete;
|
||||||
|
Client(Client&& other)
|
||||||
|
: pid(other.pid), name(std::move(other.name)), revision(std::move(other.revision)),
|
||||||
|
socket(std::move(other.socket)), ping(other.ping), current_game(other.current_game)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Client& other) const
|
||||||
|
{
|
||||||
|
return this == &other;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0);
|
void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0);
|
||||||
unsigned int OnConnect(sf::SocketTCP& socket);
|
unsigned int OnConnect(std::unique_ptr<sf::TcpSocket>& socket);
|
||||||
unsigned int OnDisconnect(sf::SocketTCP& socket);
|
unsigned int OnDisconnect(Client& player);
|
||||||
unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket);
|
unsigned int OnData(sf::Packet& packet, Client& player);
|
||||||
void UpdatePadMapping();
|
void UpdatePadMapping();
|
||||||
void UpdateWiimoteMapping();
|
void UpdateWiimoteMapping();
|
||||||
|
|
||||||
|
@ -80,7 +95,7 @@ private:
|
||||||
PadMapping m_pad_map[4];
|
PadMapping m_pad_map[4];
|
||||||
PadMapping m_wiimote_map[4];
|
PadMapping m_wiimote_map[4];
|
||||||
|
|
||||||
std::map<sf::SocketTCP, Client> m_players;
|
std::list<Client> m_players;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -91,9 +106,9 @@ private:
|
||||||
|
|
||||||
std::string m_selected_game;
|
std::string m_selected_game;
|
||||||
|
|
||||||
sf::SocketTCP m_socket;
|
sf::TcpListener m_socket;
|
||||||
std::thread m_thread;
|
std::thread m_thread;
|
||||||
sf::Selector<sf::SocketTCP> m_selector;
|
sf::SocketSelector m_selector;
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
static void mapPortThread(const u16 port);
|
static void mapPortThread(const u16 port);
|
||||||
|
|
|
@ -172,20 +172,20 @@ void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::Http::Request req;
|
sf::Http::Request req;
|
||||||
req.SetURI("/txt.php?txt=" + gameid);
|
req.setUri("/txt.php?txt=" + gameid);
|
||||||
|
|
||||||
sf::Http http;
|
sf::Http http;
|
||||||
http.SetHost("geckocodes.org");
|
http.setHost("geckocodes.org");
|
||||||
|
|
||||||
const sf::Http::Response resp = http.SendRequest(req, 5.0f);
|
const sf::Http::Response resp = http.sendRequest(req, sf::seconds(5));
|
||||||
|
|
||||||
if (sf::Http::Response::Ok == resp.GetStatus())
|
if (sf::Http::Response::Ok == resp.getStatus())
|
||||||
{
|
{
|
||||||
// temp vector containing parsed codes
|
// temp vector containing parsed codes
|
||||||
std::vector<GeckoCode> gcodes;
|
std::vector<GeckoCode> gcodes;
|
||||||
|
|
||||||
// parse the codes
|
// parse the codes
|
||||||
std::istringstream ss(resp.GetBody());
|
std::istringstream ss(resp.getBody());
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions>USE_UPNP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>USE_UPNP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions>PSAPI_VERSION=1;_M_X86=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>PSAPI_VERSION=1;_M_X86=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PreprocessorDefinitions>SFML_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">_ARCH_64=1;_M_X86_64=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">_ARCH_64=1;_M_X86_64=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
|
Loading…
Reference in New Issue