/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. IceTech Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with IceTech Source Code. If not, see . In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #include "precompiled.h" #pragma hdrstop /* ============================================================================== idBitMsg ============================================================================== */ /* ================ idBitMsg::idBitMsg ================ */ idBitMsg::idBitMsg() { writeData = NULL; readData = NULL; maxSize = 0; curSize = 0; writeBit = 0; readCount = 0; readBit = 0; allowOverflow = false; overflowed = false; } /* ================ idBitMsg::CheckOverflow ================ */ bool idBitMsg::CheckOverflow(int numBits) { assert(numBits >= 0); if (numBits > GetRemainingWriteBits()) { if (!allowOverflow) { #ifdef QUAKE4 idLib::common->FatalError(va("idBitMsg: overflow without allowOverflow set: %d > %d*8", GetNumBitsWritten() + numBits, GetMaxSize())); #else idLib::common->FatalError("idBitMsg: overflow without allowOverflow set"); #endif } if (numBits > (maxSize << 3)) { idLib::common->FatalError("idBitMsg: %i bits is > full message size", numBits); } idLib::common->Printf("idBitMsg: overflow\n"); BeginWriting(); overflowed = true; return true; } return false; } /* ================ idBitMsg::GetByteSpace ================ */ byte* idBitMsg::GetByteSpace(int length) { byte* ptr; if (!writeData) { idLib::common->FatalError("idBitMsg::GetByteSpace: cannot write to message"); } // round up to the next byte WriteByteAlign(); // check for overflow CheckOverflow(length << 3); ptr = writeData + curSize; curSize += length; return ptr; } /* ================ idBitMsg::WriteBits If the number of bits is negative a sign is included. ================ */ void idBitMsg::WriteBits(int value, int numBits) { int put; int fraction; if (!writeData) { idLib::common->Error("idBitMsg::WriteBits: cannot write to message"); } // check if the number of bits is valid if (numBits == 0 || numBits < -31 || numBits > 32) { idLib::common->Error("idBitMsg::WriteBits: bad numBits %i", numBits); } // check for value overflows // this should be an error really, as it can go unnoticed and cause either bandwidth or corrupted data transmitted if (numBits != 32) { if (numBits > 0) { if (value > (1 << numBits) - 1) { idLib::common->Warning("idBitMsg::WriteBits: value overflow %d %d", value, numBits); } else if (value < 0) { idLib::common->Warning("idBitMsg::WriteBits: value overflow %d %d", value, numBits); } } else { int r = 1 << (-1 - numBits); if (value > r - 1) { idLib::common->Warning("idBitMsg::WriteBits: value overflow %d %d", value, numBits); } else if (value < -r) { idLib::common->Warning("idBitMsg::WriteBits: value overflow %d %d", value, numBits); } } } if (numBits < 0) { numBits = -numBits; } // check for msg overflow if (CheckOverflow(numBits)) { return; } // write the bits while (numBits) { if (writeBit == 0) { writeData[curSize] = 0; curSize++; } put = 8 - writeBit; if (put > numBits) { put = numBits; } fraction = value & ((1 << put) - 1); writeData[curSize - 1] |= fraction << writeBit; numBits -= put; value >>= put; writeBit = (writeBit + put) & 7; } } /* ================ idBitMsg::WriteString ================ */ void idBitMsg::WriteString(const char* s, int maxLength, bool make7Bit) { if (!s) { WriteData("", 1); } else { int i, l; byte* dataPtr; const byte* bytePtr; l = idStr::Length(s); if (maxLength >= 0 && l >= maxLength) { l = maxLength - 1; } dataPtr = GetByteSpace(l + 1); #ifdef QUAKE4 // Quake 4 writes the string bytes as-is instead of forcing high-bit bytes to '.'. memcpy(dataPtr, s, l); #else bytePtr = reinterpret_cast(s); if (make7Bit) { for (i = 0; i < l; i++) { if (bytePtr[i] > 127) { dataPtr[i] = '.'; } else { dataPtr[i] = bytePtr[i]; } } } else { for (i = 0; i < l; i++) { dataPtr[i] = bytePtr[i]; } } #endif dataPtr[l] = '\0'; } } /* ================ idBitMsg::WriteData ================ */ void idBitMsg::WriteData(const void* data, int length) { memcpy(GetByteSpace(length), data, length); } /* ================ idBitMsg::WriteNetadr ================ */ void idBitMsg::WriteNetadr(const netadr_t adr) { byte* dataPtr; dataPtr = GetByteSpace(4); memcpy(dataPtr, adr.ip, 4); WriteUShort(adr.port); } /* ================ idBitMsg::WriteDelta ================ */ void idBitMsg::WriteDelta(int oldValue, int newValue, int numBits) { if (oldValue == newValue) { WriteBits(0, 1); return; } WriteBits(1, 1); WriteBits(newValue, numBits); } /* ================ idBitMsg::WriteDeltaByteCounter ================ */ void idBitMsg::WriteDeltaByteCounter(int oldValue, int newValue) { int i, x; x = oldValue ^ newValue; for (i = 7; i > 0; i--) { if (x & (1 << i)) { i++; break; } } WriteBits(i, 3); if (i) { WriteBits(((1 << i) - 1) & newValue, i); } } /* ================ idBitMsg::WriteDeltaShortCounter ================ */ void idBitMsg::WriteDeltaShortCounter(int oldValue, int newValue) { int i, x; x = oldValue ^ newValue; for (i = 15; i > 0; i--) { if (x & (1 << i)) { i++; break; } } WriteBits(i, 4); if (i) { WriteBits(((1 << i) - 1) & newValue, i); } } /* ================ idBitMsg::WriteDeltaLongCounter ================ */ void idBitMsg::WriteDeltaLongCounter(int oldValue, int newValue) { int i, x; x = oldValue ^ newValue; for (i = 31; i > 0; i--) { if (x & (1 << i)) { i++; break; } } WriteBits(i, 5); if (i) { WriteBits(((1 << i) - 1) & newValue, i); } } /* ================== idBitMsg::WriteDeltaDict ================== */ bool idBitMsg::WriteDeltaDict(const idDict& dict, const idDict* base) { int i; const idKeyValue* kv, * basekv; bool changed = false; if (base != NULL) { for (i = 0; i < dict.GetNumKeyVals(); i++) { kv = dict.GetKeyVal(i); basekv = base->FindKey(kv->GetKey()); if (basekv == NULL || basekv->GetValue() #ifdef QUAKE4 .Cmp(kv->GetValue()) #else .Icmp(kv->GetValue()) #endif != 0) { WriteString(kv->GetKey()); WriteString(kv->GetValue()); changed = true; } } WriteString(""); for (i = 0; i < base->GetNumKeyVals(); i++) { basekv = base->GetKeyVal(i); kv = dict.FindKey(basekv->GetKey()); if (kv == NULL) { WriteString(basekv->GetKey()); changed = true; } } WriteString(""); } else { for (i = 0; i < dict.GetNumKeyVals(); i++) { kv = dict.GetKeyVal(i); WriteString(kv->GetKey()); WriteString(kv->GetValue()); changed = true; } WriteString(""); WriteString(""); } return changed; } /* ================ idBitMsg::ReadBits If the number of bits is negative a sign is included. ================ */ int idBitMsg::ReadBits(int numBits) const { int value; int valueBits; int get; int fraction; bool sgn; if (!readData) { idLib::common->FatalError("idBitMsg::ReadBits: cannot read from message"); } // check if the number of bits is valid if (numBits == 0 || numBits < -31 || numBits > 32) { idLib::common->FatalError("idBitMsg::ReadBits: bad numBits %i", numBits); } value = 0; valueBits = 0; if (numBits < 0) { numBits = -numBits; sgn = true; } else { sgn = false; } // check for overflow if (numBits > GetRemainingReadBits()) { return -1; } while (valueBits < numBits) { if (readBit == 0) { readCount++; } get = 8 - readBit; if (get > (numBits - valueBits)) { get = numBits - valueBits; } fraction = readData[readCount - 1]; fraction >>= readBit; fraction &= (1 << get) - 1; value |= fraction << valueBits; valueBits += get; readBit = (readBit + get) & 7; } if (sgn) { if (value & (1 << (numBits - 1))) { value |= -1 ^ ((1 << numBits) - 1); } } return value; } /* ================ idBitMsg::ReadString ================ */ int idBitMsg::ReadString(char* buffer, int bufferSize) const { int l, c; ReadByteAlign(); l = 0; while (1) { c = ReadByte(); if (c <= 0 || c >= 255) { break; } // translate all fmt spec to avoid crash bugs in string routines if (c == '%') { c = '.'; } // we will read past any excessively long string, so // the following data can be read, but the string will // be truncated if (l < bufferSize - 1) { buffer[l] = c; l++; } } buffer[l] = 0; return l; } /* ================ idBitMsg::ReadData ================ */ int idBitMsg::ReadData(void* data, int length) const { int cnt; ReadByteAlign(); cnt = readCount; if (readCount + length > curSize) { if (data) { #ifdef QUAKE4 memcpy(data, readData + readCount, GetRemainingData()); #else memcpy(data, readData + readCount, GetRemaingData()); #endif } readCount = curSize; } else { if (data) { memcpy(data, readData + readCount, length); } readCount += length; } return (readCount - cnt); } /* ================ idBitMsg::ReadNetadr ================ */ void idBitMsg::ReadNetadr(netadr_t* adr) const { int i; adr->type = NA_IP; for (i = 0; i < 4; i++) { adr->ip[i] = ReadByte(); } adr->port = ReadUShort(); } /* ================ idBitMsg::ReadDelta ================ */ int idBitMsg::ReadDelta(int oldValue, int numBits) const { if (ReadBits(1)) { return ReadBits(numBits); } return oldValue; } /* ================ idBitMsg::ReadDeltaByteCounter ================ */ int idBitMsg::ReadDeltaByteCounter(int oldValue) const { int i, newValue; i = ReadBits(3); if (!i) { return oldValue; } newValue = ReadBits(i); return (oldValue & ~((1 << i) - 1) | newValue); } /* ================ idBitMsg::ReadDeltaShortCounter ================ */ int idBitMsg::ReadDeltaShortCounter(int oldValue) const { int i, newValue; i = ReadBits(4); if (!i) { return oldValue; } newValue = ReadBits(i); return (oldValue & ~((1 << i) - 1) | newValue); } /* ================ idBitMsg::ReadDeltaLongCounter ================ */ int idBitMsg::ReadDeltaLongCounter(int oldValue) const { int i, newValue; i = ReadBits(5); if (!i) { return oldValue; } newValue = ReadBits(i); return (oldValue & ~((1 << i) - 1) | newValue); } /* ================== idBitMsg::ReadDeltaDict ================== */ bool idBitMsg::ReadDeltaDict(idDict& dict, const idDict* base) const { char key[MAX_STRING_CHARS]; char value[MAX_STRING_CHARS]; bool changed = false; if (base != NULL) { dict = *base; } else { dict.Clear(); } while (ReadString(key, sizeof(key)) != 0) { ReadString(value, sizeof(value)); dict.Set(key, value); changed = true; } while (ReadString(key, sizeof(key)) != 0) { dict.Delete(key); changed = true; } return changed; } /* ================ idBitMsg::DirToBits ================ */ int idBitMsg::DirToBits(const idVec3& dir, int numBits) { int max, bits; float bias; assert(numBits >= 6 && numBits <= 32); assert(dir.LengthSqr() - 1.0f < 0.01f); numBits /= 3; max = (1 << (numBits - 1)) - 1; bias = 0.5f / max; bits = FLOATSIGNBITSET(dir.x) << (numBits * 3 - 1); bits |= (idMath::Ftoi((idMath::Fabs(dir.x) + bias) * max)) << (numBits * 2); bits |= FLOATSIGNBITSET(dir.y) << (numBits * 2 - 1); bits |= (idMath::Ftoi((idMath::Fabs(dir.y) + bias) * max)) << (numBits * 1); bits |= FLOATSIGNBITSET(dir.z) << (numBits * 1 - 1); bits |= (idMath::Ftoi((idMath::Fabs(dir.z) + bias) * max)) << (numBits * 0); return bits; } /* ================ idBitMsg::BitsToDir ================ */ idVec3 idBitMsg::BitsToDir(int bits, int numBits) { static float sign[2] = { 1.0f, -1.0f }; int max; float invMax; idVec3 dir; assert(numBits >= 6 && numBits <= 32); numBits /= 3; max = (1 << (numBits - 1)) - 1; invMax = 1.0f / max; dir.x = sign[(bits >> (numBits * 3 - 1)) & 1] * ((bits >> (numBits * 2)) & max) * invMax; dir.y = sign[(bits >> (numBits * 2 - 1)) & 1] * ((bits >> (numBits * 1)) & max) * invMax; dir.z = sign[(bits >> (numBits * 1 - 1)) & 1] * ((bits >> (numBits * 0)) & max) * invMax; dir.NormalizeFast(); return dir; } /* ============================================================================== idBitMsgDelta ============================================================================== */ const int MAX_DATA_BUFFER = 1024; /* ================ idBitMsgDelta::WriteBits ================ */ void idBitMsgDelta::WriteBits(int value, int numBits) { if (newBase) { newBase->WriteBits(value, numBits); } if (!base) { writeDelta->WriteBits(value, numBits); changed = true; } else { int baseValue = base->ReadBits(numBits); if (baseValue == value) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteBits(value, numBits); changed = true; } } } /* ================ idBitMsgDelta::WriteDelta ================ */ void idBitMsgDelta::WriteDelta(int oldValue, int newValue, int numBits) { if (newBase) { newBase->WriteBits(newValue, numBits); } if (!base) { if (oldValue == newValue) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteBits(newValue, numBits); } changed = true; } else { int baseValue = base->ReadBits(numBits); if (baseValue == newValue) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); if (oldValue == newValue) { writeDelta->WriteBits(0, 1); changed = true; } else { writeDelta->WriteBits(1, 1); writeDelta->WriteBits(newValue, numBits); changed = true; } } } } /* ================ idBitMsgDelta::ReadBits ================ */ int idBitMsgDelta::ReadBits(int numBits) const { int value; if (!base) { value = readDelta->ReadBits(numBits); changed = true; } else { int baseValue = base->ReadBits(numBits); if (!readDelta || readDelta->ReadBits(1) == 0) { value = baseValue; } else { value = readDelta->ReadBits(numBits); changed = true; } } if (newBase) { newBase->WriteBits(value, numBits); } return value; } /* ================ idBitMsgDelta::ReadDelta ================ */ int idBitMsgDelta::ReadDelta(int oldValue, int numBits) const { int value; if (!base) { if (readDelta->ReadBits(1) == 0) { value = oldValue; } else { value = readDelta->ReadBits(numBits); } changed = true; } else { int baseValue = base->ReadBits(numBits); if (!readDelta || readDelta->ReadBits(1) == 0) { value = baseValue; } else if (readDelta->ReadBits(1) == 0) { value = oldValue; changed = true; } else { value = readDelta->ReadBits(numBits); changed = true; } } if (newBase) { newBase->WriteBits(value, numBits); } return value; } /* ================ idBitMsgDelta::WriteString ================ */ void idBitMsgDelta::WriteString(const char* s, int maxLength) { if (newBase) { newBase->WriteString(s, maxLength); } if (!base) { writeDelta->WriteString(s, maxLength); changed = true; } else { char baseString[MAX_DATA_BUFFER]; base->ReadString(baseString, sizeof(baseString)); if (idStr::Cmp(s, baseString) == 0) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteString(s, maxLength); changed = true; } } } /* ================ idBitMsgDelta::WriteData ================ */ void idBitMsgDelta::WriteData(const void* data, int length) { if (newBase) { newBase->WriteData(data, length); } if (!base) { writeDelta->WriteData(data, length); changed = true; } else { byte baseData[MAX_DATA_BUFFER]; assert(length < sizeof(baseData)); base->ReadData(baseData, length); if (memcmp(data, baseData, length) == 0) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteData(data, length); changed = true; } } } /* ================ idBitMsgDelta::WriteDict ================ */ void idBitMsgDelta::WriteDict(const idDict& dict) { if (newBase) { newBase->WriteDeltaDict(dict, NULL); } if (!base) { writeDelta->WriteDeltaDict(dict, NULL); changed = true; } else { idDict baseDict; base->ReadDeltaDict(baseDict, NULL); changed = writeDelta->WriteDeltaDict(dict, &baseDict); } } /* ================ idBitMsgDelta::WriteDeltaByteCounter ================ */ void idBitMsgDelta::WriteDeltaByteCounter(int oldValue, int newValue) { if (newBase) { newBase->WriteBits(newValue, 8); } if (!base) { writeDelta->WriteDeltaByteCounter(oldValue, newValue); changed = true; } else { int baseValue = base->ReadBits(8); if (baseValue == newValue) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteDeltaByteCounter(oldValue, newValue); changed = true; } } } /* ================ idBitMsgDelta::WriteDeltaShortCounter ================ */ void idBitMsgDelta::WriteDeltaShortCounter(int oldValue, int newValue) { if (newBase) { newBase->WriteBits(newValue, 16); } if (!base) { writeDelta->WriteDeltaShortCounter(oldValue, newValue); changed = true; } else { int baseValue = base->ReadBits(16); if (baseValue == newValue) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteDeltaShortCounter(oldValue, newValue); changed = true; } } } /* ================ idBitMsgDelta::WriteDeltaLongCounter ================ */ void idBitMsgDelta::WriteDeltaLongCounter(int oldValue, int newValue) { if (newBase) { newBase->WriteBits(newValue, 32); } if (!base) { writeDelta->WriteDeltaLongCounter(oldValue, newValue); changed = true; } else { int baseValue = base->ReadBits(32); if (baseValue == newValue) { writeDelta->WriteBits(0, 1); } else { writeDelta->WriteBits(1, 1); writeDelta->WriteDeltaLongCounter(oldValue, newValue); changed = true; } } } /* ================ idBitMsgDelta::ReadString ================ */ void idBitMsgDelta::ReadString(char* buffer, int bufferSize) const { if (!base) { readDelta->ReadString(buffer, bufferSize); changed = true; } else { char baseString[MAX_DATA_BUFFER]; base->ReadString(baseString, sizeof(baseString)); if (!readDelta || readDelta->ReadBits(1) == 0) { idStr::Copynz(buffer, baseString, bufferSize); } else { readDelta->ReadString(buffer, bufferSize); changed = true; } } if (newBase) { newBase->WriteString(buffer); } } /* ================ idBitMsgDelta::ReadData ================ */ void idBitMsgDelta::ReadData(void* data, int length) const { if (!base) { readDelta->ReadData(data, length); changed = true; } else { char baseData[MAX_DATA_BUFFER]; assert(length < sizeof(baseData)); base->ReadData(baseData, length); if (!readDelta || readDelta->ReadBits(1) == 0) { memcpy(data, baseData, length); } else { readDelta->ReadData(data, length); changed = true; } } if (newBase) { newBase->WriteData(data, length); } } /* ================ idBitMsgDelta::ReadDict ================ */ void idBitMsgDelta::ReadDict(idDict& dict) { if (!base) { readDelta->ReadDeltaDict(dict, NULL); changed = true; } else { idDict baseDict; base->ReadDeltaDict(baseDict, NULL); if (!readDelta) { dict = baseDict; } else { changed = readDelta->ReadDeltaDict(dict, &baseDict); } } if (newBase) { newBase->WriteDeltaDict(dict, NULL); } } /* ================ idBitMsgDelta::ReadDeltaByteCounter ================ */ int idBitMsgDelta::ReadDeltaByteCounter(int oldValue) const { int value; if (!base) { value = readDelta->ReadDeltaByteCounter(oldValue); changed = true; } else { int baseValue = base->ReadBits(8); if (!readDelta || readDelta->ReadBits(1) == 0) { value = baseValue; } else { value = readDelta->ReadDeltaByteCounter(oldValue); changed = true; } } if (newBase) { newBase->WriteBits(value, 8); } return value; } /* ================ idBitMsgDelta::ReadDeltaShortCounter ================ */ int idBitMsgDelta::ReadDeltaShortCounter(int oldValue) const { int value; if (!base) { value = readDelta->ReadDeltaShortCounter(oldValue); changed = true; } else { int baseValue = base->ReadBits(16); if (!readDelta || readDelta->ReadBits(1) == 0) { value = baseValue; } else { value = readDelta->ReadDeltaShortCounter(oldValue); changed = true; } } if (newBase) { newBase->WriteBits(value, 16); } return value; } /* ================ idBitMsgDelta::ReadDeltaLongCounter ================ */ int idBitMsgDelta::ReadDeltaLongCounter(int oldValue) const { int value; if (!base) { value = readDelta->ReadDeltaLongCounter(oldValue); changed = true; } else { int baseValue = base->ReadBits(32); if (!readDelta || readDelta->ReadBits(1) == 0) { value = baseValue; } else { value = readDelta->ReadDeltaLongCounter(oldValue); changed = true; } } if (newBase) { newBase->WriteBits(value, 32); } return value; } #ifdef QUAKE4 /* =========================================================================== idMsgQueue =========================================================================== */ /* =============== idMsgQueue::idMsgQueue =============== */ idMsgQueue::idMsgQueue(void) { Init(0); } /* =============== idMsgQueue::Init =============== */ void idMsgQueue::Init(int sequence) { first = last = sequence; startIndex = endIndex = 0; } /* =============== idMsgQueue::Add =============== */ bool idMsgQueue::Add(const byte* data, const int size, bool sequencing) { if (GetSpaceLeft() < size + 8) { return false; } assert(size); WriteUShort(size); if (sequencing) { WriteLong(last); } last++; WriteData(data, size); return true; } /* =============== idMsgQueue::AddConcat =============== */ bool idMsgQueue::AddConcat(const byte* data1, const int size1, const byte* data2, const int size2, bool sequencing) { if (GetSpaceLeft() < size1 + size2 + 8) { return false; } assert(size1 && size2); WriteUShort(size1 + size2); if (sequencing) { WriteLong(last); } last++; WriteData(data1, size1); WriteData(data2, size2); return true; } /* =============== idMsgQueue::Get =============== */ bool idMsgQueue::Get(byte* data, int dataSize, int& size, bool sequencing) { if (sequencing ? (first == last) : (startIndex == endIndex)) { size = 0; return false; } int sequence; size = ReadUShort(); if (data && size > dataSize) { common->Error("idMsgQueue::Get buffer size of %d < get size of %d", dataSize, size); } if (sequencing) { sequence = ReadLong(); assert(sequence == first); } ReadData(data, size); first++; return true; } /* =============== idMsgQueue::GetTotalSize =============== */ int idMsgQueue::GetTotalSize(void) const { if (startIndex <= endIndex) { return (endIndex - startIndex); } else { return (sizeof(buffer) - startIndex + endIndex); } } /* =============== idMsgQueue::GetSpaceLeft =============== */ int idMsgQueue::GetSpaceLeft(void) const { if (startIndex <= endIndex) { return sizeof(buffer) - (endIndex - startIndex) - 1; } else { return (startIndex - endIndex) - 1; } } /* =============== idMsgQueue::CopyToBuffer =============== */ void idMsgQueue::CopyToBuffer(byte* buf) const { if (startIndex <= endIndex) { // RAVEN BEGIN // JSinger: Changed to call optimized memcpy SIMDProcessor->Memcpy(buf, buffer + startIndex, endIndex - startIndex); // RAVEN END } else { // RAVEN BEGIN // JSinger: Changed to call optimized memcpy SIMDProcessor->Memcpy(buf, buffer + startIndex, sizeof(buffer) - startIndex); SIMDProcessor->Memcpy(buf + sizeof(buffer) - startIndex, buffer, endIndex); // RAVEN END } } /* =============== idMsgQueue::WriteByte =============== */ void idMsgQueue::WriteByte(byte b) { buffer[endIndex] = b; endIndex = (endIndex + 1) & (MAX_MSG_QUEUE_SIZE - 1); } /* =============== idMsgQueue::ReadByte =============== */ byte idMsgQueue::ReadByte(void) { byte b = buffer[startIndex]; startIndex = (startIndex + 1) & (MAX_MSG_QUEUE_SIZE - 1); return b; } /* =============== idMsgQueue::WriteShort =============== */ void idMsgQueue::WriteShort(int s) { WriteByte((s >> 0) & 255); WriteByte((s >> 8) & 255); } /* =============== idMsgQueue::WriteUShort =============== */ void idMsgQueue::WriteUShort(int s) { WriteByte((s >> 0) & 255); WriteByte((s >> 8) & 255); } /* =============== idMsgQueue::ReadShort =============== */ int idMsgQueue::ReadShort(void) { // RAVEN BEGIN // ddynerman: removed side-effecting bitwise or byte l = ReadByte(); byte h = ReadByte(); return (short)(l | (h << 8)); // sign extend // RAVEN LOW } /* =============== idMsgQueue::ReadUShort =============== */ int idMsgQueue::ReadUShort(void) { // RAVEN BEGIN // ddynerman: removed side-effecting bitwise or byte l = ReadByte(); byte h = ReadByte(); return l | (h << 8); // RAVEN LOW } /* =============== idMsgQueue::WriteLong =============== */ void idMsgQueue::WriteLong(int l) { WriteByte((l >> 0) & 255); WriteByte((l >> 8) & 255); WriteByte((l >> 16) & 255); WriteByte((l >> 24) & 255); } /* =============== idMsgQueue::ReadLong =============== */ int idMsgQueue::ReadLong(void) { // RAVEN BEGIN // ddynerman: removed side-effecting bitwise or byte ll = ReadByte(); byte lh = ReadByte(); byte hl = ReadByte(); byte hh = ReadByte(); return ll | (lh << 8) | (hl << 16) | (hh << 24); // RAVEN END } /* =============== idMsgQueue::WriteData =============== */ void idMsgQueue::WriteData(const byte* data, const int size) { for (int i = 0; i < size; i++) { WriteByte(data[i]); } } /* =============== idMsgQueue::ReadData =============== */ void idMsgQueue::ReadData(byte* data, const int size) { if (data) { for (int i = 0; i < size; i++) { data[i] = ReadByte(); } } else { for (int i = 0; i < size; i++) { ReadByte(); } } } /* =============== idMsgQueue::WriteTo =============== */ void idMsgQueue::WriteTo(idBitMsg& msg) { msg.WriteUShort(GetTotalSize()); assert(startIndex == 0); msg.WriteData(buffer + startIndex, endIndex - startIndex); } /* =============== idMsgQueue::FlushTo =============== */ void idMsgQueue::FlushTo(idBitMsg& msg) { WriteTo(msg); Init(0); } /* =============== idMsgQueue::ReadFrom =============== */ void idMsgQueue::ReadFrom(const idBitMsg& msg) { Init(0); endIndex = msg.ReadUShort(); msg.ReadData(buffer, endIndex); } /* =============== idMsgQueue::Save =============== */ void idMsgQueue::Save(idFile* file) const { file->WriteInt(first); file->WriteInt(last); file->WriteInt(startIndex); file->WriteInt(endIndex); file->Write(buffer + startIndex, endIndex - startIndex); } /* =============== idMsgQueue::Restore =============== */ void idMsgQueue::Restore(idFile* file) { file->ReadInt(first); file->ReadInt(last); file->ReadInt(startIndex); file->ReadInt(endIndex); file->Read(buffer + startIndex, endIndex - startIndex); } /* =============== idBitMsgQueue::idBitMsgQueue =============== */ idBitMsgQueue::idBitMsgQueue(void) { Init(); } /* =============== idBitMsgQueue::Init =============== */ void idBitMsgQueue::Init(void) { readTimestamp = false; writeList.Clear(); readList.Clear(); } /* =============== idBitMsgQueue::Add =============== */ void idBitMsgQueue::Add(const idBitMsg& msg, const int timestamp) { while (writeList.NextNode() && writeList.Next()->GetSpaceLeft() < (msg.GetSize() + 8 + 4)) { writeList.NextNode()->AddToEnd(readList); } if (!writeList.NextNode()) { idLinkList< idMsgQueue >* node = new idLinkList< idMsgQueue >; node->SetOwner(new idMsgQueue); node->AddToEnd(writeList); } writeList.Next()->WriteLong(timestamp); if (!writeList.Next()->Add(msg.GetData(), msg.GetSize(), false)) { assert(false); } } /* =============== idBitMsgQueue::Get =============== */ bool idBitMsgQueue::Get(idBitMsg& msg, int& timestamp) { while (readList.NextNode() && !readList.Next()->GetTotalSize()) { readList.Next()->Init(0); readList.NextNode()->AddToEnd(writeList); } if (readList.NextNode()) { int size; timestamp = readTimestamp ? nextTimestamp : readList.Next()->ReadLong(); readTimestamp = true; if (readList.Next()->Get(msg.GetData(), msg.GetMaxSize(), size, false)) { msg.SetSize(size); msg.BeginReading(); readTimestamp = false; return true; } assert(false); } else if (writeList.NextNode() && writeList.Next()->GetTotalSize()) { int size; timestamp = readTimestamp ? nextTimestamp : writeList.Next()->ReadLong(); readTimestamp = true; if (writeList.Next()->Get(msg.GetData(), msg.GetMaxSize(), size, false)) { msg.SetSize(size); msg.BeginReading(); readTimestamp = false; return true; } assert(false); } msg.SetSize(0); return false; } /* =============== idBitMsgQueue::GetTimestamp =============== */ bool idBitMsgQueue::GetTimestamp(int& timestamp) { if (readTimestamp) { timestamp = nextTimestamp; return true; } while (readList.NextNode() && !readList.Next()->GetTotalSize()) { readList.Next()->Init(0); readList.NextNode()->AddToEnd(writeList); } if (readList.NextNode()) { timestamp = nextTimestamp = readList.Next()->ReadLong(); readTimestamp = true; return true; } else if (writeList.NextNode() && writeList.Next()->GetTotalSize()) { timestamp = nextTimestamp = writeList.Next()->ReadLong(); readTimestamp = true; return true; } return false; } #endif