// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #ifdef _WIN32 #include #else #include #endif #include #include #include "network/packet.h" namespace Network { #ifndef htonll static u64 htonll(u64 x) { return ((1 == htonl(1)) ? (x) : ((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32)); } #endif #ifndef ntohll static u64 ntohll(u64 x) { return ((1 == ntohl(1)) ? (x) : ((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32)); } #endif void Packet::Append(const void* in_data, std::size_t size_in_bytes) { if (in_data && (size_in_bytes > 0)) { std::size_t start = data.size(); data.resize(start + size_in_bytes); std::memcpy(&data[start], in_data, size_in_bytes); } } void Packet::Read(void* out_data, std::size_t size_in_bytes) { if (out_data && CheckSize(size_in_bytes)) { std::memcpy(out_data, &data[read_pos], size_in_bytes); read_pos += size_in_bytes; } } void Packet::Clear() { data.clear(); read_pos = 0; is_valid = true; } const void* Packet::GetData() const { return !data.empty() ? &data[0] : nullptr; } void Packet::IgnoreBytes(u32 length) { read_pos += length; } std::size_t Packet::GetDataSize() const { return data.size(); } bool Packet::EndOfPacket() const { return read_pos >= data.size(); } Packet::operator bool() const { return is_valid; } Packet& Packet::Read(bool& out_data) { u8 value{}; if (Read(value)) { out_data = (value != 0); } return *this; } Packet& Packet::Read(s8& out_data) { Read(&out_data, sizeof(out_data)); return *this; } Packet& Packet::Read(u8& out_data) { Read(&out_data, sizeof(out_data)); return *this; } Packet& Packet::Read(s16& out_data) { s16 value{}; Read(&value, sizeof(value)); out_data = ntohs(value); return *this; } Packet& Packet::Read(u16& out_data) { u16 value{}; Read(&value, sizeof(value)); out_data = ntohs(value); return *this; } Packet& Packet::Read(s32& out_data) { s32 value{}; Read(&value, sizeof(value)); out_data = ntohl(value); return *this; } Packet& Packet::Read(u32& out_data) { u32 value{}; Read(&value, sizeof(value)); out_data = ntohl(value); return *this; } Packet& Packet::Read(s64& out_data) { s64 value{}; Read(&value, sizeof(value)); out_data = ntohll(value); return *this; } Packet& Packet::Read(u64& out_data) { u64 value{}; Read(&value, sizeof(value)); out_data = ntohll(value); return *this; } Packet& Packet::Read(float& out_data) { Read(&out_data, sizeof(out_data)); return *this; } Packet& Packet::Read(double& out_data) { Read(&out_data, sizeof(out_data)); return *this; } Packet& Packet::Read(char* out_data) { // First extract string length u32 length = 0; Read(length); if ((length > 0) && CheckSize(length)) { // Then extract characters std::memcpy(out_data, &data[read_pos], length); out_data[length] = '\0'; // Update reading position read_pos += length; } return *this; } Packet& Packet::Read(std::string& out_data) { // First extract string length u32 length = 0; Read(length); out_data.clear(); if ((length > 0) && CheckSize(length)) { // Then extract characters out_data.assign(&data[read_pos], length); // Update reading position read_pos += length; } return *this; } Packet& Packet::Write(bool in_data) { Write(static_cast(in_data)); return *this; } Packet& Packet::Write(s8 in_data) { Append(&in_data, sizeof(in_data)); return *this; } Packet& Packet::Write(u8 in_data) { Append(&in_data, sizeof(in_data)); return *this; } Packet& Packet::Write(s16 in_data) { s16 toWrite = htons(in_data); Append(&toWrite, sizeof(toWrite)); return *this; } Packet& Packet::Write(u16 in_data) { u16 toWrite = htons(in_data); Append(&toWrite, sizeof(toWrite)); return *this; } Packet& Packet::Write(s32 in_data) { s32 toWrite = htonl(in_data); Append(&toWrite, sizeof(toWrite)); return *this; } Packet& Packet::Write(u32 in_data) { u32 toWrite = htonl(in_data); Append(&toWrite, sizeof(toWrite)); return *this; } Packet& Packet::Write(s64 in_data) { s64 toWrite = htonll(in_data); Append(&toWrite, sizeof(toWrite)); return *this; } Packet& Packet::Write(u64 in_data) { u64 toWrite = htonll(in_data); Append(&toWrite, sizeof(toWrite)); return *this; } Packet& Packet::Write(float in_data) { Append(&in_data, sizeof(in_data)); return *this; } Packet& Packet::Write(double in_data) { Append(&in_data, sizeof(in_data)); return *this; } Packet& Packet::Write(const char* in_data) { // First insert string length u32 length = static_cast(std::strlen(in_data)); Write(length); // Then insert characters Append(in_data, length * sizeof(char)); return *this; } Packet& Packet::Write(const std::string& in_data) { // First insert string length u32 length = static_cast(in_data.size()); Write(length); // Then insert characters if (length > 0) Append(in_data.c_str(), length * sizeof(std::string::value_type)); return *this; } bool Packet::CheckSize(std::size_t size) { is_valid = is_valid && (read_pos + size <= data.size()); return is_valid; } } // namespace Network