Merge pull request #1522 from jcowgill/sfml-2.1

Update / Port to SFML 2.1
This commit is contained in:
skidau 2014-11-26 12:33:03 +11:00
commit b806680eac
64 changed files with 7516 additions and 4325 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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})

View File

@ -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">

View File

@ -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>

View File

@ -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

View File

@ -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).
///
////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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.
///
////////////////////////////////////////////////////////////

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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.
///
////////////////////////////////////////////////////////////

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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.
///
////////////////////////////////////////////////////////////

View File

@ -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.
///
////////////////////////////////////////////////////////////

View File

@ -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
///
////////////////////////////////////////////////////////////

View File

@ -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)
///
////////////////////////////////////////////////////////////

View File

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

24
Externals/SFML/license.txt vendored Normal file
View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

110
Externals/SFML/src/SFML/System/Err.cpp vendored Normal file
View File

@ -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

View File

@ -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

239
Externals/SFML/src/SFML/System/Time.cpp vendored Normal file
View File

@ -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

View File

@ -238,6 +238,7 @@ set(LIBS
inputcommon inputcommon
${LZO} ${LZO}
sfml-network sfml-network
sfml-system
videoogl videoogl
videosoftware videosoftware
z z

View File

@ -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)
{ {

View File

@ -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

View File

@ -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],

View File

@ -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];
}; };

View File

@ -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());

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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())

View File

@ -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);

View File

@ -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;

View File

@ -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>