// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include "common/common_types.h" namespace Network { /// A class for serialize data for network transfer. It also handles endianess class Packet { /// A bool-like type that cannot be converted to integer or pointer types typedef bool (Packet::*BoolType)(std::size_t); public: Packet(); ~Packet(); /** * Append data to the end of the packet * @param data Pointer to the sequence of bytes to append * @param size_in_bytes Number of bytes to append */ void Append(const void* data, std::size_t size_in_bytes); /** * Reads data from the current read position of the packet * @param out_data Pointer where the data should get written to * @param size_in_bytes Number of bytes to read */ void Read(void* out_data, std::size_t size_in_bytes); /** * Clear the packet * After calling Clear, the packet is empty. */ void Clear(); /** * Ignores bytes while reading * @param length THe number of bytes to ignore */ void IgnoreBytes(u32 length); /** * Get a pointer to the data contained in the packet * @return Pointer to the data */ const void* GetData() const; /** * This function returns the number of bytes pointed to by * what getData returns. * @return Data size, in bytes */ std::size_t GetDataSize() const; /** * 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 */ bool EndOfPacket() const; /** * 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 */ operator BoolType() const; /// Overloads of operator >> to read data from the packet Packet& operator>>(bool& out_data); Packet& operator>>(s8& out_data); Packet& operator>>(u8& out_data); Packet& operator>>(s16& out_data); Packet& operator>>(u16& out_data); Packet& operator>>(s32& out_data); Packet& operator>>(u32& out_data); Packet& operator>>(float& out_data); Packet& operator>>(double& out_data); Packet& operator>>(char* out_data); Packet& operator>>(std::string& out_data); template Packet& operator>>(std::vector& out_data); template Packet& operator>>(std::array& out_data); /// Overloads of operator << to write data into the packet Packet& operator<<(bool in_data); Packet& operator<<(s8 in_data); Packet& operator<<(u8 in_data); Packet& operator<<(s16 in_data); Packet& operator<<(u16 in_data); Packet& operator<<(s32 in_data); Packet& operator<<(u32 in_data); Packet& operator<<(float in_data); Packet& operator<<(double in_data); Packet& operator<<(const char* in_data); Packet& operator<<(const std::string& in_data); template Packet& operator<<(const std::vector& in_data); template Packet& operator<<(const std::array& data); private: /// Disallow comparisons between packets bool operator==(const Packet& right) const; bool operator!=(const Packet& right) const; /** * 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 size bytes can be read from the packet */ bool CheckSize(std::size_t size); // Member data std::vector data; ///< Data stored in the packet std::size_t read_pos; ///< Current reading position in the packet bool is_valid; ///< Reading state of the packet }; template Packet& Packet::operator>>(std::vector& out_data) { for (u32 i = 0; i < out_data.size(); ++i) { T character = 0; *this >> character; out_data[i] = character; } return *this; } template Packet& Packet::operator>>(std::array& out_data) { for (u32 i = 0; i < out_data.size(); ++i) { T character = 0; *this >> character; out_data[i] = character; } return *this; } template Packet& Packet::operator<<(const std::vector& in_data) { for (u32 i = 0; i < in_data.size(); ++i) { *this << in_data[i]; } return *this; } template Packet& Packet::operator<<(const std::array& in_data) { for (u32 i = 0; i < in_data.size(); ++i) { *this << in_data[i]; } return *this; } } // namespace Network