1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-02 09:37:52 +01:00
libtgvoip/tools/Buffers.cpp

268 lines
5.9 KiB
C++
Raw Normal View History

2020-01-22 12:43:51 +01:00
//
// 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 <stdlib.h>
#include "tools/logging.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)
{
this->buffer = *buffer;
this->length = buffer.Length();
offset = 0;
}
BufferInputStream::~BufferInputStream()
{
}
void BufferInputStream::Seek(size_t offset)
{
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()
{
EnsureEnoughRemaining(1);
return (unsigned char)buffer[offset++];
}
int32_t BufferInputStream::ReadInt32()
{
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()
{
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()
{
EnsureEnoughRemaining(2);
int16_t res = (uint16_t)buffer[offset] | ((uint16_t)buffer[offset + 1] << 8);
offset += 2;
return res;
}
2020-01-23 18:06:11 +01:00
uint32_t BufferInputStream::ReadTlLength()
2020-01-22 12:43:51 +01:00
{
unsigned char l = ReadByte();
if (l < 254)
return l;
assert(length - offset >= 3);
EnsureEnoughRemaining(3);
2020-01-23 18:06:11 +01:00
uint32_t res = ((uint32_t)buffer[offset] & 0xFF) |
2020-01-25 16:04:52 +01:00
(((uint32_t)buffer[offset + 1] & 0xFF) << 8) |
(((uint32_t)buffer[offset + 2] & 0xFF) << 16);
2020-01-22 12:43:51 +01:00
offset += 3;
return res;
}
void BufferInputStream::ReadBytes(unsigned char *to, size_t count)
{
EnsureEnoughRemaining(count);
memcpy(to, buffer + offset, count);
offset += count;
}
void BufferInputStream::ReadBytes(Buffer &to)
{
ReadBytes(*to, to.Length());
}
BufferInputStream BufferInputStream::GetPartBuffer(size_t length, bool advance)
{
EnsureEnoughRemaining(length);
BufferInputStream s = BufferInputStream(buffer + offset, length);
if (advance)
offset += length;
return s;
}
void BufferInputStream::EnsureEnoughRemaining(size_t need)
{
if (length - offset < need)
{
throw std::out_of_range("Not enough bytes in buffer");
}
}
#pragma mark - BufferOutputStream
2020-01-25 16:13:16 +01:00
BufferOutputStream::BufferOutputStream(size_t size_)
: size(size_),
bufferProvided(false)
2020-01-22 12:43:51 +01:00
{
2020-01-25 16:13:16 +01:00
buffer = (unsigned char *)malloc(size_);
if (!buffer)
throw std::bad_alloc();
bufferProvided = false;
2020-01-22 12:43:51 +01:00
}
2020-01-25 16:13:16 +01:00
BufferOutputStream::BufferOutputStream(unsigned char *buffer_, size_t size_)
: buffer(buffer_),
size(size_),
bufferProvided(true)
2020-01-22 12:43:51 +01:00
{
}
BufferOutputStream::~BufferOutputStream()
{
2020-01-25 16:13:16 +01:00
if (!bufferProvided && buffer)
free(buffer);
2020-01-22 12:43:51 +01:00
}
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);
}
unsigned char *BufferOutputStream::GetBuffer()
{
return buffer;
}
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");
}
if (need < 1024)
{
buffer = (unsigned char *)realloc(buffer, size + 1024);
size += 1024;
}
else
{
buffer = (unsigned char *)realloc(buffer, size + need);
size += need;
}
if (!buffer)
throw std::bad_alloc();
}
}
void BufferOutputStream::Reset()
{
offset = 0;
}
void BufferOutputStream::Rewind(size_t numBytes)
{
if (numBytes > offset)
throw std::out_of_range("buffer underflow");
offset -= numBytes;
}