#pragma once /** * \file DataBuffer.h * \brief File containing the td::DataBuffer class */ #include #include #include #include #include #include namespace td { /** * \class DataBuffer * \brief Class used to manipulate memory */ class DataBuffer { private: typedef std::vector Data; Data m_Buffer; std::size_t m_ReadOffset; public: typedef Data::iterator iterator; typedef Data::const_iterator const_iterator; typedef Data::reference reference; typedef Data::const_reference const_reference; typedef Data::difference_type difference_type; DataBuffer(); DataBuffer(const DataBuffer& other); DataBuffer(const DataBuffer& other, difference_type offset); DataBuffer(DataBuffer&& other); DataBuffer(const std::string& str); DataBuffer& operator=(const DataBuffer& other); DataBuffer& operator=(DataBuffer&& other); /** * \brief Append data to the buffer */ template void Append(const T& data) { std::size_t size = sizeof(data); std::size_t end_pos = m_Buffer.size(); m_Buffer.resize(m_Buffer.size() + size); std::memcpy(&m_Buffer[end_pos], &data, size); } /** * \brief Append data to the buffer */ template DataBuffer& operator<<(const T& data) { Append(data); return *this; } /** * \brief Append a string to the buffer * \warning Don't use it for binary data ! * \param str The string to append */ DataBuffer& operator<<(const std::string& str) { std::size_t strlen = str.length() + 1; // including null character Resize(GetSize() + strlen); std::memcpy(m_Buffer.data() + GetSize() - strlen, str.data(), strlen); return *this; } /** * \brief Append data to the buffer from another const buffer * \param data The buffer to append */ DataBuffer& operator<<(const DataBuffer& data) { m_Buffer.insert(m_Buffer.end(), data.begin(), data.end()); return *this; } /** * \brief Read some data from the buffer and assign to desired variable */ template DataBuffer& operator>>(T& data) { assert(m_ReadOffset + sizeof(T) <= GetSize()); data = *(reinterpret_cast(&m_Buffer[m_ReadOffset])); m_ReadOffset += sizeof(T); return *this; } /** * \brief Read some data from the buffer and assign to the new buffer * \param data The buffer to assign */ DataBuffer& operator>>(DataBuffer& data) { data.Resize(GetSize() - m_ReadOffset); std::copy(m_Buffer.begin() + static_cast(m_ReadOffset), m_Buffer.end(), data.begin()); m_ReadOffset = m_Buffer.size(); return *this; } /** * \brief Read a string from the buffer * \param str The string to assign in the new buffer * \warning Don't use it for binary data ! */ DataBuffer& operator>>(std::string& str) { std::size_t stringSize = strlen(reinterpret_cast(m_Buffer.data()) + m_ReadOffset) + 1; // including null character str.resize(stringSize); std::copy(m_Buffer.begin() + static_cast(m_ReadOffset), m_Buffer.begin() + static_cast(m_ReadOffset + stringSize), str.begin()); m_ReadOffset += stringSize; return *this; } /** * \brief Write some data to the buffer * \param buffer The buffer to write * \param amount The amount of data to write */ void WriteSome(const char* buffer, std::size_t amount) { std::size_t end_pos = m_Buffer.size(); m_Buffer.resize(m_Buffer.size() + amount); std::memcpy(m_Buffer.data() + end_pos, buffer, amount); } /** * \brief Write some data to the buffer * \param buffer The buffer to write * \param amount The amount of data to write */ void WriteSome(const std::uint8_t* buffer, std::size_t amount) { std::size_t end_pos = m_Buffer.size(); m_Buffer.resize(m_Buffer.size() + amount); std::memcpy(m_Buffer.data() + end_pos, buffer, amount); } /** * \brief Read some data from the buffer * \param buffer The buffer to Read * \param amount The amount of data from the buffer */ void ReadSome(char* buffer, std::size_t amount) { assert(m_ReadOffset + amount <= GetSize()); std::copy_n(m_Buffer.begin() + static_cast(m_ReadOffset), amount, buffer); m_ReadOffset += amount; } /** * \brief Read some data from the buffer * \param buffer The buffer to Read * \param amount The amount of data from the buffer */ void ReadSome(std::uint8_t* buffer, std::size_t amount) { assert(m_ReadOffset + amount <= GetSize()); std::copy_n(m_Buffer.begin() + static_cast(m_ReadOffset), amount, buffer); m_ReadOffset += amount; } /** * \brief Read some data from the buffer * \param buffer The buffer to Read * \param amount The amount of data from the buffer */ void ReadSome(DataBuffer& buffer, std::size_t amount) { assert(m_ReadOffset + amount <= GetSize()); buffer.Resize(amount); std::copy_n(m_Buffer.begin() + static_cast(m_ReadOffset), amount, buffer.begin()); m_ReadOffset += amount; } /** * \brief Resize the buffer * \param size The new size of the buffer */ void Resize(std::size_t size) { m_Buffer.resize(size); } /** * \brief Reserve some space in the buffer * \param amount The amount of space to reserve */ void Reserve(std::size_t amount) { m_Buffer.reserve(amount); } /** * \brief Clear the buffer */ void Clear() { m_Buffer.clear(); m_ReadOffset = 0; } /** * \brief When the buffer has been read entirely */ bool IsFinished() const { return m_ReadOffset >= m_Buffer.size(); } /** * \brief Get the buffer data */ std::uint8_t* data() { return m_Buffer.data(); } /** * \brief Get the buffer data */ const std::uint8_t* data() const { return m_Buffer.data(); } /** * \brief Get the read offset */ std::size_t GetReadOffset() const { return m_ReadOffset; } /** * \brief Set the read offset * \param pos The new read offset */ void SetReadOffset(std::size_t pos); /** * \brief Get the size of the buffer */ std::size_t GetSize() const; /** * \brief Get the remaining size of the buffer */ std::size_t GetRemaining() const; /** * \brief Read a file into the buffer * \param fileName The name of the file to read */ bool ReadFile(const std::string& fileName); /** * \brief Write a file into the buffer * \param fileName The name of the file to write to */ bool WriteFile(const std::string& fileName) const; /** * \brief Allocate the buffer on the heap * \warning Don't forget to free the data ! */ std::uint8_t* HeapAllocatedData() const { std::uint8_t* newBuffer = new std::uint8_t[GetSize()]; std::memcpy(newBuffer, data(), GetSize()); return newBuffer; } /** * \brief Operator == to compare two DataBuffer */ bool operator==(const DataBuffer& other) const { return m_Buffer == other.m_Buffer; } iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; }; /** * \brief Operator << to write a DataBuffer to an ostream */ std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer); } // namespace td