Files
psopeeps-newserv/src/PSOProtocol.hh
T
2022-05-12 10:31:11 -07:00

108 lines
3.0 KiB
C++

#pragma once
#include <inttypes.h>
#include <event2/bufferevent.h>
#include <functional>
#include <phosg/Strings.hh>
#include "Version.hh"
#include "PSOEncryption.hh"
struct PSOCommandHeaderPC {
le_uint16_t size;
uint8_t command;
uint8_t flag;
} __attribute__((packed));
struct PSOCommandHeaderDCGC {
uint8_t command;
uint8_t flag;
le_uint16_t size;
} __attribute__((packed));
struct PSOCommandHeaderBB {
le_uint16_t size;
le_uint16_t command;
le_uint32_t flag;
} __attribute__((packed));
union PSOCommandHeader {
PSOCommandHeaderDCGC dc;
PSOCommandHeaderPC pc;
PSOCommandHeaderDCGC gc;
PSOCommandHeaderBB bb;
uint16_t command(GameVersion version) const;
void set_command(GameVersion version, uint16_t command);
uint16_t size(GameVersion version) const;
void set_size(GameVersion version, uint32_t size);
uint32_t flag(GameVersion version) const;
void set_flag(GameVersion version, uint32_t flag);
static inline size_t header_size(GameVersion version) {
return (version == GameVersion::BB) ? 8 : 4;
}
PSOCommandHeader();
} __attribute__((packed));
union PSOSubcommand {
uint8_t byte[4];
le_uint16_t word[2];
le_uint32_t dword;
} __attribute__((packed));
void for_each_received_command(
struct bufferevent* bev,
GameVersion version,
PSOEncryption* crypt,
std::function<void(uint16_t, uint16_t, std::string&)> fn);
void print_received_command(
uint16_t command,
uint32_t flag,
const void* data,
size_t size,
GameVersion version,
const char* name = nullptr,
TerminalFormat color = TerminalFormat::FG_GREEN);
// This function is used in a lot of places to check received command sizes and
// cast them to the appropriate type
template <typename T>
const T& check_size_t(
const std::string& data,
size_t min_size = sizeof(T),
size_t max_size = sizeof(T)) {
if (data.size() < min_size) {
throw std::runtime_error(string_printf(
"command too small (expected at least 0x%zX bytes, received 0x%zX bytes)",
min_size, data.size()));
}
if (data.size() > max_size) {
throw std::runtime_error(string_printf(
"command too large (expected at most 0x%zX bytes, received 0x%zX bytes)",
max_size, data.size()));
}
return *reinterpret_cast<const T*>(data.data());
}
template <typename T>
T& check_size_t(
std::string& data,
size_t min_size = sizeof(T),
size_t max_size = sizeof(T)) {
if (data.size() < min_size) {
throw std::runtime_error(string_printf(
"command too small (expected at least 0x%zX bytes, received 0x%zX bytes)",
min_size, data.size()));
}
if (data.size() > max_size) {
throw std::runtime_error(string_printf(
"command too large (expected at most 0x%zX bytes, received 0x%zX bytes)",
max_size, data.size()));
}
return *reinterpret_cast<T*>(data.data());
}
void check_size_v(size_t size, size_t min_size, size_t max_size = 0);