mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
get_ship(), get_wing(), get_object() and get_parse_object() only assigned their out-pointer on success. When a lookup failed (no bytes left, or a net signature that no longer resolves, e.g. a ship destroyed before the packet was processed) the caller's uninitialized local was left as stack garbage, so its nullptr check could pass and the next line would write through it. multi_sexp_set_camera_target() used the object without checking at all. Set the out-pointer to nullptr up front, so every caller's existing nullptr check works. This also clears the C4701/C4703 "potentially uninitialized" warnings MSVC 2026 reports for the callers in sexp.cpp when it inlines these getters at link time.
781 lines
20 KiB
C++
781 lines
20 KiB
C++
/*
|
|
* Created by Hassan "Karajorma" Kazmi for the FreeSpace2 Source Code Project.
|
|
* You may not sell or otherwise commercially exploit the source or things you
|
|
* create based on the source.
|
|
*/
|
|
|
|
#include "network/multi_sexp.h"
|
|
#include "parse/sexp.h"
|
|
#include "network/multi.h"
|
|
#include "network/multi_log.h"
|
|
#include "network/multiutil.h"
|
|
|
|
static const std::uint8_t CALLBACK_TERMINATOR = 255;
|
|
static const std::int16_t TEMP_DATA_SIZE = -1;
|
|
|
|
sexp_network_packet Current_sexp_network_packet;
|
|
|
|
/****************************
|
|
CLIENT SIDE PACKET FUNCTIONS
|
|
***************************/
|
|
|
|
/**
|
|
* Called when the client recieves a SEXP packet from the server. Removes the data from the packet that underlying code uses and puts
|
|
* into a new array that will work with the rest of the client-side code.
|
|
*/
|
|
void sexp_packet_received(ubyte *received_packet, int num_ubytes)
|
|
{
|
|
Current_sexp_network_packet.set_data(received_packet, num_ubytes);
|
|
|
|
// start working through the packet
|
|
multi_sexp_eval();
|
|
}
|
|
|
|
void sexp_network_packet::ensure_space_remains(size_t data_size)
|
|
{
|
|
if (!MULTIPLAYER_MASTER) {
|
|
return;
|
|
}
|
|
|
|
int packet_end = 0;
|
|
int sub_packet_size = 0;
|
|
int i, j;
|
|
|
|
// If the index of the data buffer isn't high enough yet, bail
|
|
if (packet_size + static_cast<int>(data_size) < SEXP_MAX_PACKET_SIZE) {
|
|
return;
|
|
}
|
|
|
|
//iterate back through the types array until we find a TERMINATOR and store the corresponding data index
|
|
for (i = packet_size - 1; i > 0; i--) {
|
|
if (type[i] == packet_data_type::DATA_TERMINATES) {
|
|
packet_end = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// we want the number of bytes not the index of the last one
|
|
sub_packet_size = packet_end + 1;
|
|
|
|
// At very least must include OP, COUNT, TERMINATOR
|
|
if (packet_end < MIN_SEXP_PACKET_SIZE && !packet_flagged_invalid) {
|
|
Warning(LOCATION, "Sexp %s has attempted to write too much data to a single packet. It is advised that you split this SEXP up into smaller ones", get_operator_name());
|
|
packet_flagged_invalid = true;
|
|
return;
|
|
}
|
|
|
|
send_sexp_packet(data, sub_packet_size);
|
|
|
|
j = 0;
|
|
//Slide down any entries after the stored index to the start of the array.
|
|
for (i = sub_packet_size; i < packet_size; i++) {
|
|
data[j] = data[i];
|
|
type[j] = type[i];
|
|
j++;
|
|
}
|
|
|
|
packet_size = j;
|
|
|
|
// flush the remaining type buffer
|
|
for (i = j; i < SEXP_MAX_PACKET_SIZE; i++) {
|
|
type[i] = packet_data_type::NOT_DATA;
|
|
}
|
|
|
|
// if we have an existing argument count we need to update where to put it too
|
|
if (current_argument_count) {
|
|
argument_count_index = argument_count_index - sub_packet_size;
|
|
}
|
|
|
|
Assert(argument_count_index >= 0);
|
|
}
|
|
|
|
void sexp_network_packet::reduce_counts(int amount)
|
|
{
|
|
sexp_bytes_left -= amount;
|
|
current_argument_count -= amount;
|
|
|
|
if (sexp_bytes_left < 0 || current_argument_count < 0) {
|
|
Warning(LOCATION, "multi_get_x function call has read an invalid amount of data. Trace out and fix this!");
|
|
}
|
|
}
|
|
|
|
bool sexp_network_packet::argument_count_is_valid()
|
|
{
|
|
if (current_argument_count != 0) {
|
|
// we have a problem here, either the argument count is wrong or the last SEXP didn't remove all its data from the packet
|
|
ubyte possible_terminator;
|
|
bool terminator_found = false;
|
|
for (int i = 0; i < current_argument_count; i++) {
|
|
GET_DATA(possible_terminator);
|
|
sexp_bytes_left--;
|
|
|
|
if (possible_terminator == CALLBACK_TERMINATOR) {
|
|
Warning(LOCATION, "%s has returned to multi_sexp_eval() claiming %d arguments left. %d actually found. Trace out and fix this!", get_operator_name(), current_argument_count, i);
|
|
terminator_found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we still haven't found the terminator it probably means the last SEXP didn't remove all its data from the packet
|
|
if (!terminator_found) {
|
|
GET_DATA(possible_terminator);
|
|
sexp_bytes_left--;
|
|
|
|
if (possible_terminator != CALLBACK_TERMINATOR) {
|
|
// discard remainder of packet if we still haven't found the terminator as it is hopelessly corrupt
|
|
Warning(LOCATION, "%s has returned to multi_sexp_eval() without finding the terminator. Discarding packet! Trace out and fix this!", get_operator_name());
|
|
sexp_bytes_left = 0;
|
|
return false;
|
|
}
|
|
else {
|
|
// the previous SEXP hasn't removed all it's data from the packet correctly but it appears we've managed to fix it
|
|
Warning(LOCATION, "%s has returned to multi_sexp_eval() without removing all the data the server wrote during its callback. Trace out and fix this!", get_operator_name());
|
|
op_num = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void sexp_network_packet::set_data(ubyte * received_packet, int num_ubytes)
|
|
{
|
|
offset = 0;
|
|
op_num = -1;
|
|
|
|
const auto r_data_size = std::min(SEXP_MAX_PACKET_SIZE, num_ubytes);
|
|
memcpy(data, received_packet, static_cast<size_t>(r_data_size));
|
|
|
|
sexp_bytes_left = r_data_size;
|
|
}
|
|
|
|
void sexp_network_packet::initialize()
|
|
{
|
|
if (!MULTIPLAYER_MASTER) {
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < SEXP_MAX_PACKET_SIZE; ++i) {
|
|
data[i] = 0;
|
|
type[i] = packet_data_type::NOT_DATA;
|
|
}
|
|
|
|
packet_size = 0;
|
|
argument_count_index = -1;
|
|
current_argument_count = 0;
|
|
}
|
|
|
|
void sexp_network_packet::start_callback()
|
|
{
|
|
if (!MULTIPLAYER_MASTER) {
|
|
return;
|
|
}
|
|
|
|
// Ensure that there is enough space in the packet. At present the function writes the Operator number and the argument count into the packet. Both are ints
|
|
// so we must ensure we have space left to write two ints. If this function is changed to write other data, this line MUST be updated too!
|
|
ensure_space_remains(sizeof(int) * 2);
|
|
|
|
callback_started = true;
|
|
|
|
//Write OP into the Type buffer.
|
|
type[packet_size] = packet_data_type::SEXP_OPERATOR;
|
|
//Write the SEXP_Operator number into the data buffer.
|
|
Assert(!Current_sexp_operator.empty());
|
|
ADD_INT(Current_sexp_operator.back());
|
|
|
|
//Store the next data index as we'll need it later to write the COUNT.
|
|
argument_count_index = packet_size;
|
|
// store an invalid count, we'll come back and store the correct value once we know what it is.
|
|
type[packet_size] = packet_data_type::ARGUMENT_COUNT;
|
|
ADD_SHORT(TEMP_DATA_SIZE);
|
|
}
|
|
|
|
void sexp_network_packet::end_callback()
|
|
{
|
|
if (!MULTIPLAYER_MASTER) {
|
|
return;
|
|
}
|
|
|
|
// ensure that there is enough space in the packet. If this function is ever updated to write anything other than the terminator, this MUST be taken into account here!
|
|
ensure_space_remains(sizeof(ubyte));
|
|
|
|
callback_started = false;
|
|
|
|
// something is wrong with the packet, blast it clean and start again
|
|
if (packet_flagged_invalid) {
|
|
initialize();
|
|
packet_flagged_invalid = false;
|
|
return;
|
|
}
|
|
|
|
//write TERMINATOR into the Type and data buffers
|
|
type[packet_size] = packet_data_type::DATA_TERMINATES;
|
|
ADD_DATA(CALLBACK_TERMINATOR);
|
|
|
|
//Write the COUNT into the data buffer at the index we saved earlier.
|
|
int temp_packet_size = packet_size;
|
|
packet_size = argument_count_index;
|
|
ADD_SHORT(static_cast<short>(current_argument_count));
|
|
packet_size = temp_packet_size;
|
|
|
|
current_argument_count = 0;
|
|
}
|
|
|
|
void sexp_network_packet::do_callback()
|
|
{
|
|
start_callback();
|
|
end_callback();
|
|
}
|
|
|
|
void sexp_network_packet::sexp_flush_packet()
|
|
{
|
|
if (!MULTIPLAYER_MASTER) {
|
|
return;
|
|
}
|
|
|
|
// possible to get here when there is nothing in the packet to send
|
|
if (packet_size == 0) {
|
|
return;
|
|
}
|
|
Assert(type[packet_size - 1] == packet_data_type::DATA_TERMINATES);
|
|
Assert(!packet_flagged_invalid);
|
|
|
|
send_sexp_packet(data, packet_size);
|
|
|
|
initialize();
|
|
}
|
|
|
|
bool sexp_network_packet::cannot_send_data()
|
|
{
|
|
if (!MULTIPLAYER_MASTER || packet_flagged_invalid) {
|
|
return true;
|
|
}
|
|
|
|
if (!callback_started) {
|
|
Warning(LOCATION, "Attempt to send data in multi_sexp.cpp without first starting a callback");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void sexp_network_packet::send_int(int value)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(value));
|
|
|
|
//Write INT into the Type buffer.
|
|
type[packet_size] = packet_data_type::INT;
|
|
//Write the int into the data buffer
|
|
ADD_INT(value);
|
|
//Increment the COUNT by 4 (i.e the size of an int).
|
|
current_argument_count += sizeof(int);
|
|
}
|
|
|
|
void sexp_network_packet::send_wing(wing * wingp)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(ushort));
|
|
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::WING;
|
|
//write the into the data buffer
|
|
ADD_USHORT(wingp->net_signature);
|
|
current_argument_count += sizeof(ushort);
|
|
}
|
|
|
|
void sexp_network_packet::send_ship(ship * shipp)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(ushort));
|
|
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::SHIP;
|
|
//write the into the data buffer
|
|
ADD_USHORT(Objects[shipp->objnum].net_signature);
|
|
current_argument_count += sizeof(ushort);
|
|
}
|
|
|
|
void sexp_network_packet::send_object(object * objp)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(ushort));
|
|
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::OBJECT;
|
|
//write the into the data buffer
|
|
ADD_USHORT(objp->net_signature);
|
|
current_argument_count += sizeof(ushort);
|
|
}
|
|
|
|
void sexp_network_packet::send_parse_object(p_object * pobjp)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(ushort));
|
|
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::PARSE_OBJECT;
|
|
//write the into the data buffer
|
|
ADD_USHORT(pobjp->net_signature);
|
|
current_argument_count += sizeof(ushort);
|
|
}
|
|
|
|
void sexp_network_packet::send_string(char * string)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(strlen(string) + sizeof(uint16_t));
|
|
|
|
int start_size = packet_size;
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::STRING;
|
|
//write the into the data buffer
|
|
ADD_STRING_16(string);
|
|
current_argument_count += packet_size - start_size;
|
|
}
|
|
|
|
void sexp_network_packet::send_string(const SCP_string & string)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(string.length() + sizeof(uint16_t));
|
|
|
|
int start_size = packet_size;
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::STRING;
|
|
//write the into the data buffer
|
|
ADD_STRING_16(string.c_str());
|
|
current_argument_count += packet_size - start_size;
|
|
}
|
|
|
|
void sexp_network_packet::send_bool(bool value)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(value));
|
|
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::BOOLEAN;
|
|
//Write the value into the data buffer
|
|
ADD_DATA(value);
|
|
//Increment the COUNT
|
|
current_argument_count += sizeof(value);
|
|
}
|
|
|
|
void sexp_network_packet::send_float(float value)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(value));
|
|
|
|
//write into the Type buffer.
|
|
type[packet_size] = packet_data_type::FLOAT;
|
|
//Write the value into the data buffer
|
|
ADD_FLOAT(value);
|
|
//Increment the COUNT
|
|
current_argument_count += sizeof(float);
|
|
}
|
|
|
|
void sexp_network_packet::send_vec3d(vec3d *value)
|
|
{
|
|
for (int i = 0; i < 3; ++i) // NOLINT
|
|
send_float(value->a1d[i]);
|
|
}
|
|
|
|
void sexp_network_packet::send_matrix(matrix *value)
|
|
{
|
|
for (int i = 0; i < 9; ++i) // NOLINT
|
|
send_float(value->a1d[i]);
|
|
}
|
|
|
|
void sexp_network_packet::send_short(short value)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(value));
|
|
|
|
//Write the type into the Type buffer.
|
|
type[packet_size] = packet_data_type::SHORT;
|
|
//Write the value into the data buffer
|
|
ADD_SHORT(value);
|
|
//Increment the COUNT
|
|
current_argument_count += sizeof(short);
|
|
}
|
|
|
|
void sexp_network_packet::send_ushort(ushort value)
|
|
{
|
|
if (cannot_send_data()) {
|
|
return;
|
|
}
|
|
|
|
ensure_space_remains(sizeof(value));
|
|
|
|
//Write the type into the Type buffer.
|
|
type[packet_size] = packet_data_type::USHORT;
|
|
//Write the value into the data buffer
|
|
ADD_USHORT(value);
|
|
//Increment the COUNT
|
|
current_argument_count += sizeof(ushort);
|
|
}
|
|
|
|
bool sexp_network_packet::get_int(int & value)
|
|
{
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_INT(value);
|
|
reduce_counts(sizeof(int));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_ship(int & value)
|
|
{
|
|
ushort netsig;
|
|
object *objp;
|
|
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
// get the net signature of the ship
|
|
GET_USHORT(netsig);
|
|
reduce_counts(sizeof(ushort));
|
|
|
|
// lookup the object
|
|
objp = multi_get_network_object(netsig);
|
|
if ((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >= 0)) {
|
|
value = objp->instance;
|
|
return true;
|
|
}
|
|
|
|
Warning(LOCATION, "Current_sexp_network_packet.get_ship called for net signature %d even though it is not a ship", netsig);
|
|
return false;
|
|
}
|
|
|
|
bool sexp_network_packet::get_ship(ship *& shipp)
|
|
{
|
|
int shipnum;
|
|
shipp = nullptr;
|
|
|
|
if (get_ship(shipnum)) {
|
|
shipp = &Ships[shipnum];
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool sexp_network_packet::get_wing(wing *& wingp)
|
|
{
|
|
int i;
|
|
ushort netsig;
|
|
wingp = nullptr;
|
|
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
// get the net signature of the wing
|
|
GET_USHORT(netsig);
|
|
reduce_counts(sizeof(ushort));
|
|
|
|
// lookup the wing
|
|
for (i = 0; i < Num_wings; i++) {
|
|
if (Wings[i].net_signature == netsig) {
|
|
wingp = &Wings[i];
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Warning(LOCATION, "Current_sexp_network_packet.get_wing called for net signature %d even though it is not a ship", netsig);
|
|
return false;
|
|
}
|
|
|
|
bool sexp_network_packet::get_object(object *& value)
|
|
{
|
|
ushort netsig;
|
|
value = nullptr;
|
|
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
// get the net signature of the ship
|
|
GET_USHORT(netsig);
|
|
reduce_counts(sizeof(ushort));
|
|
|
|
// lookup the object
|
|
value = multi_get_network_object(netsig);
|
|
if ((value != NULL) && (value->instance >= 0)) {
|
|
return true;
|
|
}
|
|
|
|
Warning(LOCATION, "multi_get_object called for non-existent object");
|
|
return false;
|
|
}
|
|
|
|
bool sexp_network_packet::get_parse_object(p_object *& pobjp)
|
|
{
|
|
ushort netsig;
|
|
pobjp = nullptr;
|
|
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
// get the net signature of the ship
|
|
GET_USHORT(netsig);
|
|
reduce_counts(sizeof(ushort));
|
|
|
|
// lookup the object
|
|
pobjp = mission_parse_get_arrival_ship(netsig);
|
|
if (pobjp != NULL) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool sexp_network_packet::get_string(char * buffer, const size_t buf_len)
|
|
{
|
|
char tempstring[SEXP_MAX_PACKET_SIZE];
|
|
int starting_offset = offset;
|
|
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_STRING_16(tempstring);
|
|
strcpy_s(buffer, buf_len, tempstring);
|
|
reduce_counts(offset - starting_offset);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_string(SCP_string & buffer)
|
|
{
|
|
char tempstring[SEXP_MAX_PACKET_SIZE];
|
|
int starting_offset = offset;
|
|
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_STRING_16(tempstring);
|
|
buffer = tempstring;
|
|
reduce_counts(offset - starting_offset);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_bool(bool & value)
|
|
{
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_DATA(value);
|
|
reduce_counts(sizeof(value));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_float(float & value)
|
|
{
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_FLOAT(value);
|
|
reduce_counts(sizeof(float));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_vec3d(vec3d *value)
|
|
{
|
|
for (int i = 0; i < 3; ++i) // NOLINT
|
|
{
|
|
if (!get_float(value->a1d[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_matrix(matrix *value)
|
|
{
|
|
for (int i = 0; i < 9; ++i) // NOLINT
|
|
{
|
|
if (!get_float(value->a1d[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_short(short & value)
|
|
{
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_SHORT(value);
|
|
reduce_counts(sizeof(short));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool sexp_network_packet::get_ushort(ushort & value)
|
|
{
|
|
if (!sexp_bytes_left || !current_argument_count) {
|
|
return false;
|
|
}
|
|
|
|
GET_USHORT(value);
|
|
reduce_counts(sizeof(ushort));
|
|
|
|
return true;
|
|
}
|
|
|
|
int sexp_network_packet::get_next_operator()
|
|
{
|
|
if (!argument_count_is_valid()) {
|
|
return -1;
|
|
}
|
|
|
|
short count;
|
|
|
|
GET_INT(op_num);
|
|
sexp_bytes_left -= sizeof(int);
|
|
GET_SHORT(count);
|
|
current_argument_count = count;
|
|
sexp_bytes_left -= sizeof(short);
|
|
|
|
// set index into Operators[] for debug messages
|
|
op_index = -1;
|
|
|
|
for (size_t i = 0; i < Operators.size(); ++i) {
|
|
if (Operators[i].value == op_num) {
|
|
op_index = static_cast<int>(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Assert(sexp_bytes_left);
|
|
return op_num;
|
|
|
|
}
|
|
|
|
int sexp_network_packet::get_operator()
|
|
{
|
|
return op_num;
|
|
}
|
|
|
|
const char *sexp_network_packet::get_operator_name()
|
|
{
|
|
if (op_index < 0) {
|
|
return "<unknown>";
|
|
}
|
|
|
|
return Operators[op_index].text.c_str();
|
|
}
|
|
|
|
|
|
void sexp_network_packet::finished_callback()
|
|
{
|
|
int i;
|
|
ubyte dummy;
|
|
ubyte terminator;
|
|
|
|
// For improved backwards/forwards compatibility we can discard extra data
|
|
// in the packet. NOTE that this does not provide any actual compatibility
|
|
// between builds, but can at least help reduce issues related to using
|
|
// incompatible builds.
|
|
|
|
if (current_argument_count > 0) {
|
|
// dump this to multi log for easier multi debugging in release builds
|
|
ml_printf("WARNING! Multi sexp '%s' contains %d bytes of excess/unknown data!", get_operator_name(), current_argument_count);
|
|
|
|
for (i = 0; i < current_argument_count; ++i) {
|
|
GET_DATA(dummy);
|
|
--sexp_bytes_left;
|
|
}
|
|
|
|
// clear count for the next op
|
|
current_argument_count = 0;
|
|
}
|
|
|
|
// read in the terminator
|
|
GET_DATA(terminator);
|
|
sexp_bytes_left--;
|
|
op_num = -1;
|
|
|
|
if (terminator != CALLBACK_TERMINATOR) {
|
|
Warning(LOCATION, "multi_get_x function call has been called on an improperly terminated callback. Trace out and fix this!");
|
|
// discard remainder of packet
|
|
sexp_bytes_left = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool sexp_network_packet::sexp_discard_operator()
|
|
{
|
|
int i;
|
|
ubyte dummy;
|
|
ubyte terminator;
|
|
|
|
// read in a number of bytes equal to the count
|
|
for (i = 0; i<current_argument_count; i++) {
|
|
GET_DATA(dummy);
|
|
sexp_bytes_left--;
|
|
}
|
|
|
|
// clear count for the next op
|
|
current_argument_count = 0;
|
|
|
|
GET_DATA(terminator);
|
|
sexp_bytes_left--;
|
|
op_num = -1;
|
|
|
|
// the operation terminated correctly, probably a new SEXP that this version doesn't support.
|
|
if (terminator == CALLBACK_TERMINATOR)
|
|
return true;
|
|
|
|
// packet is probably corrupt
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void sexp_network_packet::discard_remaining_callback_data()
|
|
{
|
|
if (!sexp_discard_operator()) {
|
|
Warning(LOCATION, "Attempt to discard remaining data failed! Callback lacks proper termination. Entire packet may be corrupt. Discarding remaining packet");
|
|
}
|
|
}
|