Factor out packet deserialisation functions into common file

This commit is contained in:
Jonathan G Rennison
2022-12-07 19:01:44 +00:00
parent c29b395357
commit f1f73ddd6e
4 changed files with 199 additions and 157 deletions

View File

@@ -11,6 +11,8 @@
#define SERIALISATION_HPP
#include "bitmath_func.hpp"
#include "../string_type.h"
#include "../string_func.h"
#include <vector>
#include <string>
@@ -75,4 +77,188 @@ struct BufferSerialisationHelper {
}
};
void BufferRecvStringValidate(std::string &buffer, StringValidationSettings settings);
template <typename T>
struct BufferDeserialisationHelper {
private:
const byte *GetBuffer()
{
return static_cast<T *>(this)->GetDeserialisationBuffer();
}
size_t GetBufferSize()
{
return static_cast<T *>(this)->GetDeserialisationBufferSize();
}
public:
bool CanRecvBytes(size_t bytes_to_read, bool raise_error = true)
{
return static_cast<T *>(this)->CanDeserialiseBytes(bytes_to_read, raise_error);
}
/**
* Read a boolean from the packet.
* @return The read data.
*/
bool Recv_bool()
{
return this->Recv_uint8() != 0;
}
/**
* Read a 8 bits integer from the packet.
* @return The read data.
*/
uint8 Recv_uint8()
{
uint8 n;
if (!this->CanRecvBytes(sizeof(n), true)) return 0;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
n = this->GetBuffer()[pos++];
return n;
}
/**
* Read a 16 bits integer from the packet.
* @return The read data.
*/
uint16 Recv_uint16()
{
uint16 n;
if (!this->CanRecvBytes(sizeof(n), true)) return 0;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
n = (uint16)this->GetBuffer()[pos++];
n += (uint16)this->GetBuffer()[pos++] << 8;
return n;
}
/**
* Read a 32 bits integer from the packet.
* @return The read data.
*/
uint32 Recv_uint32()
{
uint32 n;
if (!this->CanRecvBytes(sizeof(n), true)) return 0;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
n = (uint32)this->GetBuffer()[pos++];
n += (uint32)this->GetBuffer()[pos++] << 8;
n += (uint32)this->GetBuffer()[pos++] << 16;
n += (uint32)this->GetBuffer()[pos++] << 24;
return n;
}
/**
* Read a 64 bits integer from the packet.
* @return The read data.
*/
uint64 Recv_uint64()
{
uint64 n;
if (!this->CanRecvBytes(sizeof(n), true)) return 0;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
n = (uint64)this->GetBuffer()[pos++];
n += (uint64)this->GetBuffer()[pos++] << 8;
n += (uint64)this->GetBuffer()[pos++] << 16;
n += (uint64)this->GetBuffer()[pos++] << 24;
n += (uint64)this->GetBuffer()[pos++] << 32;
n += (uint64)this->GetBuffer()[pos++] << 40;
n += (uint64)this->GetBuffer()[pos++] << 48;
n += (uint64)this->GetBuffer()[pos++] << 56;
return n;
}
/**
* Reads characters (bytes) from the packet until it finds a '\0', or reaches a
* maximum of \c length characters.
* When the '\0' has not been reached in the first \c length read characters,
* more characters are read from the packet until '\0' has been reached. However,
* these characters will not end up in the returned string.
* The length of the returned string will be at most \c length - 1 characters.
* @param length The maximum length of the string including '\0'.
* @param settings The string validation settings.
* @return The validated string.
*/
std::string Recv_string(size_t length, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK)
{
assert(length > 1);
/* Both loops with Recv_uint8 terminate when reading past the end of the
* packet as Recv_uint8 then closes the connection and returns 0. */
std::string str;
char character;
while (--length > 0 && (character = this->Recv_uint8()) != '\0') str.push_back(character);
if (length == 0) {
/* The string in the packet was longer. Read until the termination. */
while (this->Recv_uint8() != '\0') {}
}
BufferRecvStringValidate(str, settings);
return str;
}
/**
* Reads a string till it finds a '\0' in the stream.
* @param buffer The buffer to put the data into.
* @param settings The string validation settings.
*/
void Recv_string(std::string &buffer, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK)
{
/* Don't allow reading from a closed socket */
if (!this->CanRecvBytes(0, false)) return;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
size_t length = ttd_strnlen((const char *)(this->GetBuffer() + pos), this->GetBufferSize() - pos - 1);
buffer.assign((const char *)(this->GetBuffer() + pos), length);
pos += (decltype(pos))length + 1;
BufferRecvStringValidate(buffer, settings);
}
/**
* Reads binary data.
* @param buffer The buffer to put the data into.
* @param size The size of the data.
*/
void Recv_binary(char *buffer, size_t size)
{
if (!this->CanRecvBytes(size, true)) return;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
memcpy(buffer, &this->GetBuffer()[pos], size);
pos += (decltype(pos)) size;
}
/**
* Reads binary data.
* @param buffer The buffer to put the data into.
* @param size The size of the data.
*/
void Recv_binary(std::string &buffer, size_t size)
{
if (!this->CanRecvBytes(size, true)) return;
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
buffer.assign((const char *) &this->GetBuffer()[pos], size);
pos += (decltype(pos)) size;
}
};
#endif /* SERIALISATION_HPP */