From 24c5ad1d06c34e4f3b530bdae2f6b668cda1943e Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 18 Jun 2023 22:56:20 -0700 Subject: [PATCH] handle multiple subcommands in one top-level command --- src/ReceiveCommands.cc | 2 +- src/ReceiveSubcommands.cc | 37 +++++++++++++++++++++++++++++-------- src/ReceiveSubcommands.hh | 2 +- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index a643ad75..3bc22203 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -2533,7 +2533,7 @@ static void on_6x_C9_CB(shared_ptr s, shared_ptr c, return; } - on_subcommand(s, l, c, command, flag, data); + on_subcommand_multi(s, l, c, command, flag, data); } static void on_chat_generic(shared_ptr s, shared_ptr c, diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 0a369bc8..a1ca1aa5 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -1714,21 +1714,42 @@ subcommand_handler_t subcommand_handlers[0x100] = { /* 6xFF */ nullptr, }; -void on_subcommand(shared_ptr s, shared_ptr l, +void on_subcommand_multi(shared_ptr s, shared_ptr l, shared_ptr c, uint8_t command, uint8_t flag, const string& data) { if (data.empty()) { throw runtime_error("game command is empty"); } if (c->version() == GameVersion::DC && (c->flags & (Client::Flag::IS_TRIAL_EDITION | Client::Flag::IS_DC_V1_PROTOTYPE))) { // TODO: We should convert these to non-trial formats and vice versa - forward_subcommand(l, c, command, flag, std::move(data)); + forward_subcommand(l, c, command, flag, data.data(), data.size()); } else { - uint8_t which = static_cast(data[0]); - auto fn = subcommand_handlers[which]; - if (fn) { - fn(s, l, c, command, flag, data); - } else { - on_unimplemented(s, l, c, command, flag, data); + StringReader r(data); + while (!r.eof()) { + size_t size; + const auto& header = r.get(false); + if (header.size != 0) { + size = header.size << 2; + } else { + const auto& ext_header = r.get>(false); + size = ext_header.size; + if (size < 8) { + throw runtime_error("extended subcommand header has size < 8"); + } + if (size & 3) { + throw runtime_error("extended subcommand size is not a multiple of 4"); + } + } + if (size == 0) { + throw runtime_error("invalid subcommand size"); + } + const void* data = r.getv(size); + + auto fn = subcommand_handlers[header.subcommand]; + if (fn) { + fn(s, l, c, command, flag, data, size); + } else { + on_unimplemented(s, l, c, command, flag, data, size); + } } } } diff --git a/src/ReceiveSubcommands.hh b/src/ReceiveSubcommands.hh index 2333e555..fd4619a4 100644 --- a/src/ReceiveSubcommands.hh +++ b/src/ReceiveSubcommands.hh @@ -5,7 +5,7 @@ #include "PSOProtocol.hh" #include "ServerState.hh" -void on_subcommand( +void on_subcommand_multi( std::shared_ptr s, std::shared_ptr l, std::shared_ptr c, uint8_t command, uint8_t flag, const std::string& data);