#include "bitmsg.h" #include idBitMsg::idBitMsg() : writeData(nullptr), readData(nullptr), maxSize(0), curSize(0), writeBit(0), readCount(0), readBit(0), allowOverflow(false), overflowed(false), tempValue(0) {} idBitMsg::idBitMsg(unsigned char* data, const int length) : idBitMsg() { Init(data, length); } idBitMsg::idBitMsg(const unsigned char* data, const int length) : idBitMsg() { Init(data, length); } void idBitMsg::Init(unsigned char* data, const int length) { writeData = data; readData = data; maxSize = length; BeginWriting(); } void idBitMsg::Init(const unsigned char* data, const int length) { writeData = nullptr; readData = data; maxSize = curSize = length; writeBit = 0; BeginReading(); allowOverflow = overflowed = false; tempValue = 0; } void idBitMsg::BeginWriting() { curSize = writeBit = readCount = readBit = 0; overflowed = false; tempValue = 0; } void idBitMsg::BeginReading() const { readCount = readBit = 0; } bool idBitMsg::CheckOverflow(const int numBits) { if (curSize * 8 + writeBit + numBits <= maxSize * 8) return false; if (!allowOverflow || numBits > maxSize * 8) { overflowed = true; return true; } curSize = writeBit = 0; tempValue = 0; overflowed = true; return false; } unsigned char* idBitMsg::GetByteSpace(const int length) { if (writeData == nullptr || length < 0) return nullptr; if (writeBit != 0) { ++curSize; writeBit = 0; tempValue = 0; } if (CheckOverflow(length * 8)) return nullptr; unsigned char* const result = writeData + curSize; curSize += length; return result; } void idBitMsg::WriteBits(const int value, int numBits) { if (writeData == nullptr || numBits == 0 || numBits < -31 || numBits > 32) return; if (numBits < 0) numBits = -numBits; if (CheckOverflow(numBits)) return; std::uint32_t bits = static_cast(value); if (numBits < 32) bits &= (1u << numBits) - 1u; for (int bit = 0; bit < numBits; ++bit) { if (writeBit == 0) writeData[curSize] = 0; if ((bits & (1u << bit)) != 0) writeData[curSize] |= static_cast(1u << writeBit); if (++writeBit == 8) { writeBit = 0; ++curSize; } } tempValue = writeBit != 0 ? writeData[curSize] : 0; } int idBitMsg::ReadBits(int numBits) const { if (readData == nullptr || numBits == 0 || numBits < -31 || numBits > 32) return -1; const bool signedValue = numBits < 0; if (signedValue) numBits = -numBits; const int availableBits = (curSize - readCount) * 8 + (readBit != 0 ? 8 - readBit : 0); if (numBits > availableBits) return -1; std::uint32_t result = 0; for (int bit = 0; bit < numBits; ++bit) { if (readBit == 0) ++readCount; if ((readData[readCount - 1] & (1u << readBit)) != 0) result |= 1u << bit; readBit = (readBit + 1) & 7; } if (signedValue && numBits < 32 && (result & (1u << (numBits - 1))) != 0) result |= ~((1u << numBits) - 1u); return static_cast(result); } void idBitMsg::WriteData(const void* data, const int length) { unsigned char* const destination = GetByteSpace(length); if (destination != nullptr && data != nullptr && length > 0) std::memcpy(destination, data, static_cast(length)); } int idBitMsg::ReadData(void* data, const int length) const { if (length <= 0 || readData == nullptr) return 0; readBit = 0; const int amount = (std::min)(length, curSize - readCount); if (data != nullptr && amount > 0) std::memcpy(data, readData + readCount, static_cast(amount)); readCount += amount; return amount; } void idBitMsg::WriteDelta(const int oldValue, const int newValue, const int numBits) { WriteBits(oldValue != newValue, 1); if (oldValue != newValue) WriteBits(newValue, numBits); } int idBitMsg::ReadDelta(const int oldValue, const int numBits) const { return ReadBits(1) != 0 ? ReadBits(numBits) : oldValue; } void idBitMsg::WriteString(const char* string, const int maxLength, const bool make7Bit) { const char* const source = string != nullptr ? string : ""; int length = static_cast(std::strlen(source)); if (maxLength >= 0 && length >= maxLength) length = (std::max)(0, maxLength - 1); unsigned char* const destination = GetByteSpace(length + 1); if (destination == nullptr) return; for (int index = 0; index < length; ++index) { const unsigned char value = static_cast(source[index]); destination[index] = make7Bit && value > 127 ? '.' : value; } destination[length] = 0; } int idBitMsg::ReadString(char* buffer, const int bufferSize) const { if (buffer == nullptr || bufferSize <= 0) return 0; readBit = 0; int length = 0; while (readCount < curSize) { unsigned char value = readData[readCount++]; if (value == 0 || value == 255) break; if (value == '%') value = '.'; if (length < bufferSize - 1) buffer[length++] = static_cast(value); } buffer[length] = 0; return length; } int idBitMsg::ReadString(idStr& string) const { char buffer[4096]; const int length = ReadString(buffer, sizeof(buffer)); string = buffer; return length; } void idBitMsg::WriteNetadr(const netadr_t& address) { WriteData(address.ip, 4); WriteBits(address.port, 16); WriteBits(address.type, 8); } void idBitMsg::ReadNetadr(netadr_t* address) const { if (address == nullptr) return; ReadData(address->ip, 4); address->port = static_cast(ReadBits(16)); address->type = static_cast(ReadBits(8)); } void idBitMsg::WriteDeltaShortCounter(const int oldValue, const int newValue) { const int delta = newValue - oldValue; unsigned int magnitude = delta < 0 ? -delta : delta; int bits = 1; while (magnitude >>= 1) ++bits; WriteBits(bits - 1, 4); WriteBits(delta, -(bits + 1)); } void idBitMsg::WriteDeltaLongCounter(const int oldValue, const int newValue) { const int delta = newValue - oldValue; unsigned int magnitude = delta < 0 ? -delta : delta; int bits = 1; while (magnitude >>= 1) ++bits; WriteBits(bits - 1, 5); WriteBits(delta, -(bits + 1)); } int idBitMsg::ReadDeltaShortCounter(const int oldValue) const { const int bits = ReadBits(4) + 1; return oldValue + ReadBits(-(bits + 1)); } int idBitMsg::ReadDeltaLongCounter(const int oldValue) const { const int bits = ReadBits(5) + 1; return oldValue + ReadBits(-(bits + 1)); } idFile_BitMsg::idFile_BitMsg(idBitMsg& message) : idFile(), name("*bitmsg*"), mode(FS_READ_WRITE), msg(&message) {} unsigned int idFile_BitMsg::Read(void* data, const unsigned int length) { return static_cast(msg != nullptr ? msg->ReadData(data, static_cast(length)) : 0); } unsigned int idFile_BitMsg::Write(const void* data, const unsigned int length) { if (msg == nullptr || mode == FS_READ) return 0; msg->WriteData(data, static_cast(length)); return length; } std::int64_t idFile_BitMsg::Length() const { return msg != nullptr ? msg->GetSize() : 0; } std::int64_t idFile_BitMsg::Tell() const { if (msg == nullptr) return 0; return mode == FS_READ ? msg->GetReadCount() : msg->GetSize(); }