Prevent buffer overflows when using streams
This commit is contained in:
parent
13a8b0e5ba
commit
ab7b1642bc
18 changed files with 600 additions and 388 deletions
|
|
@ -38,7 +38,10 @@
|
|||
#include "cmdlib.h"
|
||||
#include "serializer.h"
|
||||
|
||||
char* ReadString(uint8_t **stream)
|
||||
// Unchecked stream functions.
|
||||
// Use the checked versions instead unless you're checking the stream size yourself!
|
||||
|
||||
char* UncheckedReadString(uint8_t **stream)
|
||||
{
|
||||
char *string = *((char **)stream);
|
||||
|
||||
|
|
@ -46,65 +49,65 @@ char* ReadString(uint8_t **stream)
|
|||
return copystring(string);
|
||||
}
|
||||
|
||||
const char* ReadStringConst(uint8_t **stream)
|
||||
const char* UncheckedReadStringConst(uint8_t **stream)
|
||||
{
|
||||
const char *string = *((const char **)stream);
|
||||
*stream += strlen(string) + 1;
|
||||
return string;
|
||||
}
|
||||
|
||||
uint8_t ReadInt8(uint8_t **stream)
|
||||
uint8_t UncheckedReadInt8(uint8_t **stream)
|
||||
{
|
||||
uint8_t v = **stream;
|
||||
*stream += 1;
|
||||
return v;
|
||||
}
|
||||
|
||||
int16_t ReadInt16(uint8_t **stream)
|
||||
int16_t UncheckedReadInt16(uint8_t **stream)
|
||||
{
|
||||
int16_t v = (((*stream)[0]) << 8) | (((*stream)[1]));
|
||||
*stream += 2;
|
||||
return v;
|
||||
}
|
||||
|
||||
int32_t ReadInt32(uint8_t **stream)
|
||||
int32_t UncheckedReadInt32(uint8_t **stream)
|
||||
{
|
||||
int32_t v = (((*stream)[0]) << 24) | (((*stream)[1]) << 16) | (((*stream)[2]) << 8) | (((*stream)[3]));
|
||||
*stream += 4;
|
||||
return v;
|
||||
}
|
||||
|
||||
int64_t ReadInt64(uint8_t** stream)
|
||||
int64_t UncheckedReadInt64(uint8_t **stream)
|
||||
{
|
||||
int64_t v = (int64_t((*stream)[0]) << 56) | (int64_t((*stream)[1]) << 48) | (int64_t((*stream)[2]) << 40) | (int64_t((*stream)[3]) << 32)
|
||||
| (int64_t((*stream)[4]) << 24) | (int64_t((*stream)[5]) << 16) | (int64_t((*stream)[6]) << 8) | (int64_t((*stream)[7]));
|
||||
| (int64_t((*stream)[4]) << 24) | (int64_t((*stream)[5]) << 16) | (int64_t((*stream)[6]) << 8) | (int64_t((*stream)[7]));
|
||||
*stream += 8;
|
||||
return v;
|
||||
}
|
||||
|
||||
float ReadFloat(uint8_t **stream)
|
||||
float UncheckedReadFloat(uint8_t **stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t i;
|
||||
float f;
|
||||
} fakeint;
|
||||
fakeint.i = ReadInt32 (stream);
|
||||
fakeint.i = UncheckedReadInt32(stream);
|
||||
return fakeint.f;
|
||||
}
|
||||
|
||||
double ReadDouble(uint8_t** stream)
|
||||
double UncheckedReadDouble(uint8_t **stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int64_t i;
|
||||
double f;
|
||||
} fakeint;
|
||||
fakeint.i = ReadInt64(stream);
|
||||
fakeint.i = UncheckedReadInt64(stream);
|
||||
return fakeint.f;
|
||||
}
|
||||
|
||||
void WriteString(const char *string, uint8_t **stream)
|
||||
void UncheckedWriteString(const char *string, uint8_t **stream)
|
||||
{
|
||||
char *p = *((char **)stream);
|
||||
|
||||
|
|
@ -116,20 +119,20 @@ void WriteString(const char *string, uint8_t **stream)
|
|||
*stream = (uint8_t *)p;
|
||||
}
|
||||
|
||||
void WriteInt8(uint8_t v, uint8_t **stream)
|
||||
void UncheckedWriteInt8(uint8_t v, uint8_t **stream)
|
||||
{
|
||||
**stream = v;
|
||||
*stream += 1;
|
||||
}
|
||||
|
||||
void WriteInt16(int16_t v, uint8_t **stream)
|
||||
void UncheckedWriteInt16(int16_t v, uint8_t **stream)
|
||||
{
|
||||
(*stream)[0] = v >> 8;
|
||||
(*stream)[1] = v & 255;
|
||||
*stream += 2;
|
||||
}
|
||||
|
||||
void WriteInt32(int32_t v, uint8_t **stream)
|
||||
void UncheckedWriteInt32(int32_t v, uint8_t **stream)
|
||||
{
|
||||
(*stream)[0] = v >> 24;
|
||||
(*stream)[1] = (v >> 16) & 255;
|
||||
|
|
@ -138,7 +141,7 @@ void WriteInt32(int32_t v, uint8_t **stream)
|
|||
*stream += 4;
|
||||
}
|
||||
|
||||
void WriteInt64(int64_t v, uint8_t** stream)
|
||||
void UncheckedWriteInt64(int64_t v, uint8_t **stream)
|
||||
{
|
||||
(*stream)[0] = v >> 56;
|
||||
(*stream)[1] = (v >> 48) & 255;
|
||||
|
|
@ -151,7 +154,231 @@ void WriteInt64(int64_t v, uint8_t** stream)
|
|||
*stream += 8;
|
||||
}
|
||||
|
||||
void WriteFloat(float v, uint8_t **stream)
|
||||
void UncheckedWriteFloat(float v, uint8_t **stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t i;
|
||||
float f;
|
||||
} fakeint;
|
||||
fakeint.f = v;
|
||||
UncheckedWriteInt32(fakeint.i, stream);
|
||||
}
|
||||
|
||||
void UncheckedWriteDouble(double v, uint8_t **stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int64_t i;
|
||||
double f;
|
||||
} fakeint;
|
||||
fakeint.f = v;
|
||||
UncheckedWriteInt64(fakeint.i, stream);
|
||||
}
|
||||
|
||||
void AdvanceStream(TArrayView<uint8_t>& stream, size_t bytes)
|
||||
{
|
||||
assert(bytes <= stream.Size());
|
||||
stream = TArrayView(stream.Data() + bytes, stream.Size() - bytes);
|
||||
}
|
||||
|
||||
// Checked stream functions
|
||||
|
||||
char* ReadString(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
char *string = (char*)stream.Data();
|
||||
size_t len = strnlen(string, stream.Size());
|
||||
if (len == stream.Size())
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
AdvanceStream(stream, len + 1);
|
||||
return copystring(string);
|
||||
}
|
||||
|
||||
const char* ReadStringConst(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
const char* string = (const char*)stream.Data();
|
||||
size_t len = strnlen(string, stream.Size());
|
||||
if (len == stream.Size())
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
AdvanceStream(stream, len + 1);
|
||||
return string;
|
||||
}
|
||||
|
||||
void ReadBytes(TArrayView<uint8_t>& dst, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (dst.Size() > stream.Size())
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
if (dst.Size())
|
||||
{
|
||||
memcpy(dst.Data(), stream.Data(), dst.Size());
|
||||
AdvanceStream(stream, dst.Size());
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadInt8(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 1)
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
uint8_t v = stream[0];
|
||||
AdvanceStream(stream, 1);
|
||||
return v;
|
||||
}
|
||||
|
||||
int16_t ReadInt16(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 2)
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
int16_t v = ((stream[0]) << 8) | stream[1];
|
||||
AdvanceStream(stream, 2);
|
||||
return v;
|
||||
}
|
||||
|
||||
int32_t ReadInt32(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 4)
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
int32_t v = (stream[0] << 24) | (stream[1] << 16) | (stream[2] << 8) | stream[3];
|
||||
AdvanceStream(stream, 4);
|
||||
return v;
|
||||
}
|
||||
|
||||
int64_t ReadInt64(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 8)
|
||||
{
|
||||
I_Error("Attempted to read past end of stream");
|
||||
}
|
||||
int64_t v = (int64_t(stream[0]) << 56) | (int64_t(stream[1]) << 48) | (int64_t(stream[2]) << 40) | (int64_t(stream[3]) << 32)
|
||||
| (int64_t(stream[4]) << 24) | (int64_t(stream[5]) << 16) | (int64_t(stream[6]) << 8) | int64_t(stream[7]);
|
||||
AdvanceStream(stream, 8);
|
||||
return v;
|
||||
}
|
||||
|
||||
float ReadFloat(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int32_t i;
|
||||
float f;
|
||||
} fakeint;
|
||||
fakeint.i = ReadInt32 (stream);
|
||||
return fakeint.f;
|
||||
}
|
||||
|
||||
double ReadDouble(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
int64_t i;
|
||||
double f;
|
||||
} fakeint;
|
||||
fakeint.i = ReadInt64(stream);
|
||||
return fakeint.f;
|
||||
}
|
||||
|
||||
void WriteString(const char *string, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
char *p = (char *)stream.Data();
|
||||
unsigned int remaining = stream.Size();
|
||||
|
||||
while (*string) {
|
||||
if (remaining-- == 0)
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
*p++ = *string++;
|
||||
}
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
*p++ = 0;
|
||||
AdvanceStream(stream, p - (char*)stream.Data());
|
||||
}
|
||||
|
||||
void WriteBytes(const TArrayView<uint8_t>& source, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (source.Size() > stream.Size())
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
if (source.Size())
|
||||
{
|
||||
memcpy(stream.Data(), source.Data(), source.Size());
|
||||
AdvanceStream(stream, source.Size());
|
||||
}
|
||||
}
|
||||
|
||||
void WriteFString(FString& string, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
WriteBytes(string.GetTArrayView(), stream);
|
||||
}
|
||||
|
||||
void WriteInt8(uint8_t v, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 1)
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
stream[0] = v;
|
||||
AdvanceStream(stream, 1);
|
||||
}
|
||||
|
||||
void WriteInt16(int16_t v, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 2)
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
stream[0] = v >> 8;
|
||||
stream[1] = v & 255;
|
||||
AdvanceStream(stream, 2);
|
||||
}
|
||||
|
||||
void WriteInt32(int32_t v, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 4)
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
stream[0] = v >> 24;
|
||||
stream[1] = (v >> 16) & 255;
|
||||
stream[2] = (v >> 8) & 255;
|
||||
stream[3] = v & 255;
|
||||
AdvanceStream(stream, 4);
|
||||
}
|
||||
|
||||
void WriteInt64(int64_t v, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (stream.Size() < 8)
|
||||
{
|
||||
I_Error("Attempted to write past end of stream");
|
||||
}
|
||||
stream[0] = v >> 56;
|
||||
stream[1] = (v >> 48) & 255;
|
||||
stream[2] = (v >> 40) & 255;
|
||||
stream[3] = (v >> 32) & 255;
|
||||
stream[4] = (v >> 24) & 255;
|
||||
stream[5] = (v >> 16) & 255;
|
||||
stream[6] = (v >> 8) & 255;
|
||||
stream[7] = v & 255;
|
||||
AdvanceStream(stream, 8);
|
||||
}
|
||||
|
||||
void WriteFloat(float v, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
|
|
@ -162,7 +389,7 @@ void WriteFloat(float v, uint8_t **stream)
|
|||
WriteInt32 (fakeint.i, stream);
|
||||
}
|
||||
|
||||
void WriteDouble(double v, uint8_t** stream)
|
||||
void WriteDouble(double v, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
union
|
||||
{
|
||||
|
|
@ -193,11 +420,8 @@ FSerializer& Serialize(FSerializer& arc, const char* key, usercmd_t& cmd, usercm
|
|||
return arc;
|
||||
}
|
||||
|
||||
// Returns the number of bytes read
|
||||
int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
||||
void UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
const uint8_t* start = stream;
|
||||
|
||||
if (basis != nullptr)
|
||||
{
|
||||
if (basis != &cmd)
|
||||
|
|
@ -208,7 +432,7 @@ int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
|||
memset(&cmd, 0, sizeof(usercmd_t));
|
||||
}
|
||||
|
||||
uint8_t flags = ReadInt8(&stream);
|
||||
uint8_t flags = ReadInt8(stream);
|
||||
if (flags)
|
||||
{
|
||||
// We can support up to 29 buttons using 1 to 4 bytes to store them. The most
|
||||
|
|
@ -216,19 +440,19 @@ int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
|||
// should be read in excluding the last one which supports all 8 bits.
|
||||
if (flags & UCMDF_BUTTONS)
|
||||
{
|
||||
uint8_t in = ReadInt8(&stream);
|
||||
uint8_t in = ReadInt8(stream);
|
||||
uint32_t buttons = (cmd.buttons & ~0x7F) | (in & 0x7F);
|
||||
if (in & MoreButtons)
|
||||
{
|
||||
in = ReadInt8(&stream);
|
||||
in = ReadInt8(stream);
|
||||
buttons = (buttons & ~(0x7F << 7)) | ((in & 0x7F) << 7);
|
||||
if (in & MoreButtons)
|
||||
{
|
||||
in = ReadInt8(&stream);
|
||||
in = ReadInt8(stream);
|
||||
buttons = (buttons & ~(0x7F << 14)) | ((in & 0x7F) << 14);
|
||||
if (in & MoreButtons)
|
||||
{
|
||||
in = ReadInt8(&stream);
|
||||
in = ReadInt8(stream);
|
||||
buttons = (buttons & ~(0xFF << 21)) | (in << 21);
|
||||
}
|
||||
}
|
||||
|
|
@ -236,26 +460,24 @@ int UnpackUserCmd(usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
|||
cmd.buttons = buttons;
|
||||
}
|
||||
if (flags & UCMDF_PITCH)
|
||||
cmd.pitch = ReadInt16(&stream);
|
||||
cmd.pitch = ReadInt16(stream);
|
||||
if (flags & UCMDF_YAW)
|
||||
cmd.yaw = ReadInt16(&stream);
|
||||
cmd.yaw = ReadInt16(stream);
|
||||
if (flags & UCMDF_FORWARDMOVE)
|
||||
cmd.forwardmove = ReadInt16(&stream);
|
||||
cmd.forwardmove = ReadInt16(stream);
|
||||
if (flags & UCMDF_SIDEMOVE)
|
||||
cmd.sidemove = ReadInt16(&stream);
|
||||
cmd.sidemove = ReadInt16(stream);
|
||||
if (flags & UCMDF_UPMOVE)
|
||||
cmd.upmove = ReadInt16(&stream);
|
||||
cmd.upmove = ReadInt16(stream);
|
||||
if (flags & UCMDF_ROLL)
|
||||
cmd.roll = ReadInt16(&stream);
|
||||
cmd.roll = ReadInt16(stream);
|
||||
}
|
||||
|
||||
return int(stream - start);
|
||||
}
|
||||
|
||||
int PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
||||
void PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
uint8_t flags = 0;
|
||||
uint8_t* start = stream;
|
||||
auto flagsPosition = TArrayView(stream.Data(), 1);
|
||||
|
||||
usercmd_t blank;
|
||||
if (basis == nullptr)
|
||||
|
|
@ -264,7 +486,7 @@ int PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
|||
basis = ␣
|
||||
}
|
||||
|
||||
++stream; // Make room for the flags.
|
||||
AdvanceStream(stream, 1); // Make room for the flags.
|
||||
uint32_t buttons_changed = cmd.buttons ^ basis->buttons;
|
||||
if (buttons_changed != 0)
|
||||
{
|
||||
|
|
@ -284,56 +506,54 @@ int PackUserCmd(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
|||
bytes[2] |= MoreButtons;
|
||||
}
|
||||
}
|
||||
WriteInt8(bytes[0], &stream);
|
||||
WriteInt8(bytes[0], stream);
|
||||
if (bytes[0] & MoreButtons)
|
||||
{
|
||||
WriteInt8(bytes[1], &stream);
|
||||
WriteInt8(bytes[1], stream);
|
||||
if (bytes[1] & MoreButtons)
|
||||
{
|
||||
WriteInt8(bytes[2], &stream);
|
||||
WriteInt8(bytes[2], stream);
|
||||
if (bytes[2] & MoreButtons)
|
||||
WriteInt8(bytes[3], &stream);
|
||||
WriteInt8(bytes[3], stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cmd.pitch != basis->pitch)
|
||||
{
|
||||
flags |= UCMDF_PITCH;
|
||||
WriteInt16(cmd.pitch, &stream);
|
||||
WriteInt16(cmd.pitch, stream);
|
||||
}
|
||||
if (cmd.yaw != basis->yaw)
|
||||
{
|
||||
flags |= UCMDF_YAW;
|
||||
WriteInt16 (cmd.yaw, &stream);
|
||||
WriteInt16 (cmd.yaw, stream);
|
||||
}
|
||||
if (cmd.forwardmove != basis->forwardmove)
|
||||
{
|
||||
flags |= UCMDF_FORWARDMOVE;
|
||||
WriteInt16 (cmd.forwardmove, &stream);
|
||||
WriteInt16 (cmd.forwardmove, stream);
|
||||
}
|
||||
if (cmd.sidemove != basis->sidemove)
|
||||
{
|
||||
flags |= UCMDF_SIDEMOVE;
|
||||
WriteInt16(cmd.sidemove, &stream);
|
||||
WriteInt16(cmd.sidemove, stream);
|
||||
}
|
||||
if (cmd.upmove != basis->upmove)
|
||||
{
|
||||
flags |= UCMDF_UPMOVE;
|
||||
WriteInt16(cmd.upmove, &stream);
|
||||
WriteInt16(cmd.upmove, stream);
|
||||
}
|
||||
if (cmd.roll != basis->roll)
|
||||
{
|
||||
flags |= UCMDF_ROLL;
|
||||
WriteInt16(cmd.roll, &stream);
|
||||
WriteInt16(cmd.roll, stream);
|
||||
}
|
||||
|
||||
// Write the packing bits
|
||||
WriteInt8(flags, &start);
|
||||
|
||||
return int(stream - start);
|
||||
WriteInt8(flags, flagsPosition);
|
||||
}
|
||||
|
||||
int WriteUserCmdMessage(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*& stream)
|
||||
void WriteUserCmdMessage(const usercmd_t& cmd, const usercmd_t* basis, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (basis == nullptr)
|
||||
{
|
||||
|
|
@ -341,58 +561,60 @@ int WriteUserCmdMessage(const usercmd_t& cmd, const usercmd_t* basis, uint8_t*&
|
|||
|| cmd.pitch || cmd.yaw || cmd.roll
|
||||
|| cmd.forwardmove || cmd.sidemove || cmd.upmove)
|
||||
{
|
||||
WriteInt8(DEM_USERCMD, &stream);
|
||||
return PackUserCmd(cmd, basis, stream) + 1;
|
||||
WriteInt8(DEM_USERCMD, stream);
|
||||
PackUserCmd(cmd, basis, stream);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (cmd.buttons != basis->buttons
|
||||
|| cmd.yaw != basis->yaw || cmd.pitch != basis->pitch || cmd.roll != basis->roll
|
||||
|| cmd.forwardmove != basis->forwardmove || cmd.sidemove != basis->sidemove || cmd.upmove != basis->upmove)
|
||||
{
|
||||
WriteInt8(DEM_USERCMD, &stream);
|
||||
return PackUserCmd(cmd, basis, stream) + 1;
|
||||
WriteInt8(DEM_USERCMD, stream);
|
||||
PackUserCmd(cmd, basis, stream);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteInt8(DEM_EMPTYUSERCMD, &stream);
|
||||
return 1;
|
||||
WriteInt8(DEM_EMPTYUSERCMD, stream);
|
||||
}
|
||||
|
||||
// Reads through the user command without actually setting any of its info. Used to get the size
|
||||
// of the command when getting the length of the stream.
|
||||
int SkipUserCmdMessage(uint8_t*& stream)
|
||||
void SkipUserCmdMessage(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
const uint8_t* start = stream;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const uint8_t type = *stream++;
|
||||
const uint8_t type = ReadInt8(stream);
|
||||
if (type == DEM_USERCMD)
|
||||
{
|
||||
int skip = 1;
|
||||
if (*stream & UCMDF_PITCH)
|
||||
if (stream[0] & UCMDF_PITCH)
|
||||
skip += 2;
|
||||
if (*stream & UCMDF_YAW)
|
||||
if (stream[0] & UCMDF_YAW)
|
||||
skip += 2;
|
||||
if (*stream & UCMDF_FORWARDMOVE)
|
||||
if (stream[0] & UCMDF_FORWARDMOVE)
|
||||
skip += 2;
|
||||
if (*stream & UCMDF_SIDEMOVE)
|
||||
if (stream[0] & UCMDF_SIDEMOVE)
|
||||
skip += 2;
|
||||
if (*stream & UCMDF_UPMOVE)
|
||||
if (stream[0] & UCMDF_UPMOVE)
|
||||
skip += 2;
|
||||
if (*stream & UCMDF_ROLL)
|
||||
if (stream[0] & UCMDF_ROLL)
|
||||
skip += 2;
|
||||
if (*stream & UCMDF_BUTTONS)
|
||||
if (stream[0] & UCMDF_BUTTONS)
|
||||
{
|
||||
if (*++stream & MoreButtons)
|
||||
AdvanceStream(stream, 1);
|
||||
if (stream[0] & MoreButtons)
|
||||
{
|
||||
if (*++stream & MoreButtons)
|
||||
AdvanceStream(stream, 1);
|
||||
if (stream[0] & MoreButtons)
|
||||
{
|
||||
if (*++stream & MoreButtons)
|
||||
++stream;
|
||||
AdvanceStream(stream, 1);
|
||||
if (stream[0] & MoreButtons)
|
||||
AdvanceStream(stream, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
stream += skip;
|
||||
AdvanceStream(stream, skip);
|
||||
break;
|
||||
}
|
||||
else if (type == DEM_EMPTYUSERCMD)
|
||||
|
|
@ -401,31 +623,29 @@ int SkipUserCmdMessage(uint8_t*& stream)
|
|||
}
|
||||
else
|
||||
{
|
||||
Net_SkipCommand(type, &stream);
|
||||
Net_SkipCommand(type, stream);
|
||||
}
|
||||
}
|
||||
|
||||
return int(stream - start);
|
||||
}
|
||||
|
||||
int ReadUserCmdMessage(uint8_t*& stream, int player, int tic)
|
||||
void ReadUserCmdMessage(TArrayView<uint8_t>& stream, int player, int tic)
|
||||
{
|
||||
const int ticMod = tic % BACKUPTICS;
|
||||
|
||||
auto& curTic = ClientStates[player].Tics[ticMod];
|
||||
usercmd_t& ticCmd = curTic.Command;
|
||||
|
||||
const uint8_t* start = stream;
|
||||
const uint8_t* start = stream.Data();
|
||||
|
||||
// Skip until we reach the player command. Event data will get read off once the
|
||||
// tick is actually executed.
|
||||
int type;
|
||||
while ((type = ReadInt8(&stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD)
|
||||
Net_SkipCommand(type, &stream);
|
||||
while ((type = ReadInt8(stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD)
|
||||
Net_SkipCommand(type, stream);
|
||||
|
||||
// Subtract a byte to account for the fact the stream head is now sitting on the
|
||||
// user command.
|
||||
curTic.Data.SetData(start, int(stream - start - 1));
|
||||
curTic.Data.SetData(start, int(stream.Data() - start - 1));
|
||||
|
||||
if (type == DEM_USERCMD)
|
||||
{
|
||||
|
|
@ -439,8 +659,6 @@ int ReadUserCmdMessage(uint8_t*& stream, int player, int tic)
|
|||
else
|
||||
memset(&ticCmd, 0, sizeof(ticCmd));
|
||||
}
|
||||
|
||||
return int(stream - start);
|
||||
}
|
||||
|
||||
void RunPlayerCommands(int player, int tic)
|
||||
|
|
@ -449,14 +667,12 @@ void RunPlayerCommands(int player, int tic)
|
|||
if (gametic % TicDup)
|
||||
return;
|
||||
|
||||
int len;
|
||||
auto& data = ClientStates[player].Tics[tic % BACKUPTICS].Data;
|
||||
uint8_t* stream = data.GetData(&len);
|
||||
if (stream != nullptr)
|
||||
auto stream = data.GetTArrayView();
|
||||
if (stream.Size())
|
||||
{
|
||||
uint8_t* end = stream + len;
|
||||
while (stream < end)
|
||||
Net_DoCommand(ReadInt8(&stream), &stream, player);
|
||||
while (stream.Size() > 0)
|
||||
Net_DoCommand(ReadInt8(stream), stream, player);
|
||||
|
||||
if (!demorecording)
|
||||
data.SetData(nullptr, 0);
|
||||
|
|
@ -469,22 +685,23 @@ uint8_t* streamPos = nullptr;
|
|||
|
||||
// Write the header of an IFF chunk and leave space
|
||||
// for the length field.
|
||||
void StartChunk(int id, uint8_t **stream)
|
||||
void StartChunk(int id, TArrayView<uint8_t>& stream)
|
||||
{
|
||||
WriteInt32(id, stream);
|
||||
streamPos = *stream;
|
||||
*stream += 4;
|
||||
streamPos = stream.Data();
|
||||
AdvanceStream(stream, 4);
|
||||
}
|
||||
|
||||
// Write the length field for the chunk and insert
|
||||
// pad byte if the chunk is odd-sized.
|
||||
void FinishChunk(uint8_t **stream)
|
||||
void FinishChunk(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
if (streamPos == nullptr)
|
||||
return;
|
||||
|
||||
int len = int(*stream - streamPos - 4);
|
||||
WriteInt32(len, &streamPos);
|
||||
int len = int(stream.Data() - streamPos - 4);
|
||||
auto streamPosView = TArrayView<uint8_t>(streamPos, 4);
|
||||
WriteInt32(len, streamPosView);
|
||||
if (len & 1)
|
||||
WriteInt8(0, stream);
|
||||
|
||||
|
|
@ -493,8 +710,8 @@ void FinishChunk(uint8_t **stream)
|
|||
|
||||
// Skip past an unknown chunk. *stream should be
|
||||
// pointing to the chunk's length field.
|
||||
void SkipChunk(uint8_t **stream)
|
||||
void SkipChunk(TArrayView<uint8_t>& stream)
|
||||
{
|
||||
int len = ReadInt32(stream);
|
||||
*stream += len + (len & 1);
|
||||
AdvanceStream(stream, len + (len & 1));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue