summaryrefslogblamecommitdiffstats
path: root/src/network/packet.h
blob: 6d84cfbac02234070c78cf593c98afe2acdc428e (plain) (tree)































































































































































































                                                                              
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <vector>
#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 <typename T>
    Packet& operator>>(std::vector<T>& out_data);
    template <typename T, std::size_t S>
    Packet& operator>>(std::array<T, S>& 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 <typename T>
    Packet& operator<<(const std::vector<T>& in_data);
    template <typename T, std::size_t S>
    Packet& operator<<(const std::array<T, S>& 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<char> 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 <typename T>
Packet& Packet::operator>>(std::vector<T>& out_data) {
    for (u32 i = 0; i < out_data.size(); ++i) {
        T character = 0;
        *this >> character;
        out_data[i] = character;
    }
    return *this;
}

template <typename T, std::size_t S>
Packet& Packet::operator>>(std::array<T, S>& out_data) {
    for (u32 i = 0; i < out_data.size(); ++i) {
        T character = 0;
        *this >> character;
        out_data[i] = character;
    }
    return *this;
}

template <typename T>
Packet& Packet::operator<<(const std::vector<T>& in_data) {
    for (u32 i = 0; i < in_data.size(); ++i) {
        *this << in_data[i];
    }
    return *this;
}

template <typename T, std::size_t S>
Packet& Packet::operator<<(const std::array<T, S>& in_data) {
    for (u32 i = 0; i < in_data.size(); ++i) {
        *this << in_data[i];
    }
    return *this;
}

} // namespace Network