498d7ee79c
Just updating all the 2020 references to 2021. 😄
546 lines
18 KiB
C++
546 lines
18 KiB
C++
////////////////////////////////////////////////////////////
|
|
//
|
|
// SFML - Simple and Fast Multimedia Library
|
|
// Copyright (C) 2007-2021 Laurent Gomila (laurent@sfml-dev.org)
|
|
//
|
|
// 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_PACKET_HPP
|
|
#define SFML_PACKET_HPP
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Headers
|
|
////////////////////////////////////////////////////////////
|
|
#include <SFML/Network/Export.hpp>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
|
|
namespace sf
|
|
{
|
|
class String;
|
|
class TcpSocket;
|
|
class UdpSocket;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Utility class to build blocks of data to transfer
|
|
/// over the network
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
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:
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Default constructor
|
|
///
|
|
/// Creates an empty packet.
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
Packet();
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Virtual destructor
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
virtual ~Packet();
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Append data to the end of the packet
|
|
///
|
|
/// \param data Pointer to the sequence of bytes to append
|
|
/// \param sizeInBytes Number of bytes to append
|
|
///
|
|
/// \see clear
|
|
/// \see getReadPosition
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void append(const void* data, std::size_t sizeInBytes);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Get the current reading position in the packet
|
|
///
|
|
/// The next read operation will read data from this position
|
|
///
|
|
/// \return The byte offset of the current read position
|
|
///
|
|
/// \see append
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
std::size_t getReadPosition() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Clear the packet
|
|
///
|
|
/// After calling Clear, the packet is empty.
|
|
///
|
|
/// \see append
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void clear();
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Get a pointer to the data contained in 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
|
|
///
|
|
/// \see getDataSize
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
const void* getData() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \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
|
|
///
|
|
/// \see getData
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
std::size_t getDataSize() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \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 behavior 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
|
|
///
|
|
/// \see endOfPacket
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
operator BoolType() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// Overload of operator >> to read data from the packet
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(bool& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Int8& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Uint8& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Int16& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Uint16& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Int32& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Uint32& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Int64& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(Uint64& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(float& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(double& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(char* data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(std::string& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(wchar_t* data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(std::wstring& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator >>(String& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// Overload of operator << to write data into the packet
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(bool data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Int8 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Uint8 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Int16 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Uint16 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Int32 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Uint32 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Int64 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(Uint64 data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(float data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(double data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(const char* data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(const std::string& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(const wchar_t* data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(const std::wstring& data);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \overload
|
|
////////////////////////////////////////////////////////////
|
|
Packet& operator <<(const String& data);
|
|
|
|
protected:
|
|
|
|
friend class TcpSocket;
|
|
friend class UdpSocket;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Called before the packet is sent over the network
|
|
///
|
|
/// 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
|
|
///
|
|
/// \see onReceive
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
virtual const void* onSend(std::size_t& size);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Called after the packet is received over the network
|
|
///
|
|
/// This function can be defined by derived classes to
|
|
/// transform the data after it is received; this can be
|
|
/// used for decompression, 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 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
|
|
////////////////////////////////////////////////////////////
|
|
std::vector<char> m_data; //!< Data stored in the packet
|
|
std::size_t m_readPos; //!< Current reading position in the packet
|
|
std::size_t m_sendPos; //!< Current send position in the packet (for handling partial sends)
|
|
bool m_isValid; //!< Reading state of the packet
|
|
};
|
|
|
|
} // namespace sf
|
|
|
|
|
|
#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
|
|
/// transferring 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 behavior 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
|
|
///
|
|
////////////////////////////////////////////////////////////
|