1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-11-29 20:29:01 +01:00
libtgvoip/tools/Buffers.cpp
2020-03-25 21:38:07 +01:00

407 lines
9.6 KiB
C++

//
// libtgvoip is free and unencumbered public domain software.
// For more information, see http://unlicense.org or the UNLICENSE file
// you should have received with this source code distribution.
//
#include "tools/Buffers.h"
#include <assert.h>
#include <string.h>
#include <exception>
#include <stdexcept>
#include <cstdlib>
#include "tools/logging.h"
#include "controller/net/NetworkSocket.h"
#include "controller/protocol/protocol/Interface.h"
using namespace tgvoip;
#pragma mark - BufferInputStream
BufferInputStream::BufferInputStream(const unsigned char *data, const size_t _length) : buffer(data), length(_length)
{
}
BufferInputStream::BufferInputStream(const Buffer &buffer) : buffer(*buffer), length(buffer.Length())
{
}
void BufferInputStream::Seek(size_t offset) const
{
if (offset > length)
{
throw std::out_of_range("Not enough bytes in buffer");
}
this->offset = offset;
}
size_t BufferInputStream::GetLength() const
{
return length;
}
size_t BufferInputStream::GetOffset() const
{
return offset;
}
size_t BufferInputStream::Remaining() const
{
return length - offset;
}
unsigned char BufferInputStream::ReadByte() const
{
EnsureEnoughRemaining(1);
return (unsigned char)buffer[offset++];
}
int32_t BufferInputStream::ReadInt32() const
{
EnsureEnoughRemaining(4);
int32_t res = ((int32_t)buffer[offset] & 0xFF) |
(((int32_t)buffer[offset + 1] & 0xFF) << 8) |
(((int32_t)buffer[offset + 2] & 0xFF) << 16) |
(((int32_t)buffer[offset + 3] & 0xFF) << 24);
offset += 4;
return res;
}
int64_t BufferInputStream::ReadInt64() const
{
EnsureEnoughRemaining(8);
int64_t res = ((int64_t)buffer[offset] & 0xFF) |
(((int64_t)buffer[offset + 1] & 0xFF) << 8) |
(((int64_t)buffer[offset + 2] & 0xFF) << 16) |
(((int64_t)buffer[offset + 3] & 0xFF) << 24) |
(((int64_t)buffer[offset + 4] & 0xFF) << 32) |
(((int64_t)buffer[offset + 5] & 0xFF) << 40) |
(((int64_t)buffer[offset + 6] & 0xFF) << 48) |
(((int64_t)buffer[offset + 7] & 0xFF) << 56);
offset += 8;
return res;
}
int16_t BufferInputStream::ReadInt16() const
{
EnsureEnoughRemaining(2);
int16_t res = (uint16_t)buffer[offset] | ((uint16_t)buffer[offset + 1] << 8);
offset += 2;
return res;
}
uint32_t BufferInputStream::ReadTlLength() const
{
unsigned char l = ReadByte();
if (l < 254)
return l;
assert(length - offset >= 3);
EnsureEnoughRemaining(3);
uint32_t res = ((uint32_t)buffer[offset] & 0xFF) |
(((uint32_t)buffer[offset + 1] & 0xFF) << 8) |
(((uint32_t)buffer[offset + 2] & 0xFF) << 16);
offset += 3;
return res;
}
void BufferInputStream::ReadBytes(unsigned char *to, size_t count) const
{
EnsureEnoughRemaining(count);
memcpy(to, buffer + offset, count);
offset += count;
}
void BufferInputStream::ReadBytes(Buffer &to) const
{
ReadBytes(*to, to.Length());
}
BufferInputStream BufferInputStream::GetPartBuffer(size_t length, bool advance) const
{
EnsureEnoughRemaining(length);
BufferInputStream s = BufferInputStream(buffer + offset, length);
if (advance)
offset += length;
return s;
}
const unsigned char *BufferInputStream::GetRawBuffer() const
{
return buffer + offset;
}
void BufferInputStream::EnsureEnoughRemaining(size_t need) const
{
if (length - offset < need)
{
throw std::out_of_range("Not enough bytes in buffer");
}
}
bool BufferInputStream::TryRead(uint8_t &data) const
{
if (offset + 1 > length)
return false;
data = buffer[offset++];
return true;
}
bool BufferInputStream::TryRead(uint16_t &data) const
{
if (offset + 2 > length)
return false;
data = (uint16_t)buffer[offset] | ((uint16_t)buffer[offset + 1] << 8);
offset += 2;
return true;
}
bool BufferInputStream::TryRead(uint32_t &data) const
{
if (offset + 4 > length)
return false;
data = ((uint32_t)buffer[offset] & 0xFF) |
(((uint32_t)buffer[offset + 1] & 0xFF) << 8) |
(((uint32_t)buffer[offset + 2] & 0xFF) << 16) |
(((uint32_t)buffer[offset + 3] & 0xFF) << 24);
offset += 4;
return true;
}
bool BufferInputStream::TryRead(uint64_t &data) const
{
if (offset + 8 > length)
return false;
data = ((uint64_t)buffer[offset] & 0xFF) |
(((uint64_t)buffer[offset + 1] & 0xFF) << 8) |
(((uint64_t)buffer[offset + 2] & 0xFF) << 16) |
(((uint64_t)buffer[offset + 3] & 0xFF) << 24) |
(((uint64_t)buffer[offset + 4] & 0xFF) << 32) |
(((uint64_t)buffer[offset + 5] & 0xFF) << 40) |
(((uint64_t)buffer[offset + 6] & 0xFF) << 48) |
(((uint64_t)buffer[offset + 7] & 0xFF) << 56);
offset += 8;
return true;
}
bool BufferInputStream::TryRead(int16_t &data) const
{
if (offset + 2 > length)
return false;
data = (int16_t)buffer[offset] | ((int16_t)buffer[offset + 1] << 8);
offset += 2;
return true;
}
bool BufferInputStream::TryRead(int32_t &data) const
{
if (offset + 4 > length)
return false;
data = ((int32_t)buffer[offset] & 0xFF) |
(((int32_t)buffer[offset + 1] & 0xFF) << 8) |
(((int32_t)buffer[offset + 2] & 0xFF) << 16) |
(((int32_t)buffer[offset + 3] & 0xFF) << 24);
offset += 4;
return true;
}
bool BufferInputStream::TryRead(int64_t &data) const
{
if (offset + 8 > length)
return false;
data = ((int64_t)buffer[offset] & 0xFF) |
(((int64_t)buffer[offset + 1] & 0xFF) << 8) |
(((int64_t)buffer[offset + 2] & 0xFF) << 16) |
(((int64_t)buffer[offset + 3] & 0xFF) << 24) |
(((int64_t)buffer[offset + 4] & 0xFF) << 32) |
(((int64_t)buffer[offset + 5] & 0xFF) << 40) |
(((int64_t)buffer[offset + 6] & 0xFF) << 48) |
(((int64_t)buffer[offset + 7] & 0xFF) << 56);
offset += 8;
return true;
}
bool BufferInputStream::TryRead(uint8_t *to, size_t len) const
{
if (offset + len > length)
return false;
memcpy(to, buffer + offset, len);
offset += len;
return true;
}
bool BufferInputStream::TryRead(Buffer &to) const
{
return TryRead(*to, to.Length());
}
bool BufferInputStream::TryRead(NetworkAddress &to, bool ipv6) const
{
to.isIPv6 = ipv6;
return ipv6 ? TryRead(to.addr.ipv6, 16) : TryRead(to.addr.ipv4);
}
bool BufferInputStream::TryRead(Serializable &to, const VersionInfo &ver) const
{
return to.parse(*this, ver);
}
bool BufferInputStream::Has(size_t len) const
{
return offset + len > length;
}
bool BufferInputStream::TryReadTlLength(uint32_t &data) const
{
uint8_t byte;
if (!TryRead(byte))
{
return false;
}
if (byte < 254)
{
data = byte;
return true;
}
if (length - offset < 3)
{
return false;
}
data = ((uint32_t)buffer[offset] & 0xFF) |
(((uint32_t)buffer[offset + 1] & 0xFF) << 8) |
(((uint32_t)buffer[offset + 2] & 0xFF) << 16);
offset += 3;
return true;
}
#pragma mark - BufferOutputStream
BufferOutputStream::BufferOutputStream(size_t size_)
: size(size_),
bufferProvided(false)
{
buffer = reinterpret_cast<unsigned char *>(std::malloc(size_));
if (!buffer)
throw std::bad_alloc();
bufferProvided = false;
}
BufferOutputStream::BufferOutputStream(unsigned char *buffer_, size_t size_)
: buffer(buffer_),
size(size_),
bufferProvided(true)
{
}
BufferOutputStream::~BufferOutputStream()
{
if (!bufferProvided && buffer)
free(buffer);
}
void BufferOutputStream::WriteByte(unsigned char byte)
{
this->ExpandBufferIfNeeded(1);
buffer[offset++] = byte;
}
void BufferOutputStream::WriteInt32(int32_t i)
{
this->ExpandBufferIfNeeded(4);
buffer[offset + 3] = (unsigned char)((i >> 24) & 0xFF);
buffer[offset + 2] = (unsigned char)((i >> 16) & 0xFF);
buffer[offset + 1] = (unsigned char)((i >> 8) & 0xFF);
buffer[offset] = (unsigned char)(i & 0xFF);
offset += 4;
}
void BufferOutputStream::WriteInt64(int64_t i)
{
this->ExpandBufferIfNeeded(8);
buffer[offset + 7] = (unsigned char)((i >> 56) & 0xFF);
buffer[offset + 6] = (unsigned char)((i >> 48) & 0xFF);
buffer[offset + 5] = (unsigned char)((i >> 40) & 0xFF);
buffer[offset + 4] = (unsigned char)((i >> 32) & 0xFF);
buffer[offset + 3] = (unsigned char)((i >> 24) & 0xFF);
buffer[offset + 2] = (unsigned char)((i >> 16) & 0xFF);
buffer[offset + 1] = (unsigned char)((i >> 8) & 0xFF);
buffer[offset] = (unsigned char)(i & 0xFF);
offset += 8;
}
void BufferOutputStream::WriteInt16(int16_t i)
{
this->ExpandBufferIfNeeded(2);
buffer[offset + 1] = (unsigned char)((i >> 8) & 0xFF);
buffer[offset] = (unsigned char)(i & 0xFF);
offset += 2;
}
void BufferOutputStream::WriteBytes(const unsigned char *bytes, size_t count)
{
this->ExpandBufferIfNeeded(count);
memcpy(buffer + offset, bytes, count);
offset += count;
}
void BufferOutputStream::WriteBytes(const Buffer &buffer)
{
WriteBytes(*buffer, buffer.Length());
}
void BufferOutputStream::WriteBytes(const Buffer &buffer, size_t offset, size_t count)
{
if (offset + count > buffer.Length())
throw std::out_of_range("offset out of buffer bounds");
WriteBytes(*buffer + offset, count);
}
void BufferOutputStream::Write(const Serializable &data, const VersionInfo &ver)
{
data.serialize(*this, ver);
}
unsigned char *BufferOutputStream::GetBuffer()
{
return buffer;
}
size_t BufferOutputStream::GetOffset()
{
return offset;
}
size_t BufferOutputStream::GetLength()
{
return offset;
}
void BufferOutputStream::ExpandBufferIfNeeded(size_t need)
{
if (offset + need > size)
{
if (bufferProvided)
{
throw std::out_of_range("buffer overflow");
}
size += std::max(need, size_t{1024});
unsigned char *newBuffer = reinterpret_cast<unsigned char *>(std::realloc(buffer, size));
if (!newBuffer)
{
std::free(buffer);
buffer = nullptr;
size = 0;
throw std::bad_alloc();
}
buffer = newBuffer;
}
}
void BufferOutputStream::Reset()
{
offset = 0;
}
void BufferOutputStream::Rewind(size_t numBytes)
{
if (numBytes > offset)
throw std::out_of_range("buffer underflow");
offset -= numBytes;
}
void BufferOutputStream::Advance(size_t numBytes)
{
ExpandBufferIfNeeded(numBytes);
offset += numBytes;
}