Loading...   

  • Created By Uleat On: 07:13 PM August 08, 2015
  • Link

/*
EQEMu:  Everquest Server Emulator

Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net)

This program 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; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#pragma once

#include <string>
#include <assert.h>

#include "typedefs.h"

template<size_t size> class safe_buffer
{
public:
	// ctors
	safe_buffer() {
		assert(size && ~size);
		clear();
	}

	safe_buffer(const char* dataRef, size_t dataCount = 0) {
		assert(size && ~size);
		assign(dataRef, dataCount);
	}

	safe_buffer(const std::string& dataRef, size_t dataCount = 0) {
		assert(size && ~size);
		assign(dataRef, dataCount);
	}

	// dtor
	~safe_buffer();

	// propery accessors
	size_t size() {
		return m_size;
	}

	size_t used() {
		return m_used;
	}

	size_t free() {
		return m_free;
	}

	size_t last() {
		return m_last;
	}

	// methods
	size_t append(const char* dataRef, size_t dataCount = 0) {
		if (dataRef == nullptr)
			return failed();
		if (dataCount > m_free)
			dataCount = m_free;
		if (m_free == 0)
			return failed();
		if (dataCount)
			return append_count(dataRef, dataCount);
		else
			return append_nullterm(dataRef);
	}

	size_t append(const std::string& dataRef, size_t dataCount = 0) {
		if (dataCount > dataRef.length())
			dataCount = dataRef.length();
		if (dataCount > m_free)
			dataCount = m_free;
		if (m_free == 0)
			return failed();
		if (dataCount)
			return append_count(dataRef.c_str(), dataCount);
		else
			return append_nullterm(dataRef.c_str());
	}

	size_t assign(const char* dataRef, size_t dataCount) {
		clear();
		return append(dataRef, dataCount);
	}

	size_t assign(const std::string& dataRef, size_t dataCount) {
		clear();
		return append(dataRef, dataCount);
	}

	const char* buffer(size_t dataPos = 0) {
		if (dataPos >= m_size)
			return nullptr;
		return &m_buffer[dataPos];
	}

	void clear() {
		memset(&m_buffer, 0, m_size + 1);
		m_used = 0;
		m_free = m_size;
		m_last = 0;
	}

	size_t concatenate(size_t dataPos) {
		if (dataPos >= m_used)
			return m_used;
		if (dataPos == 0)
			return m_used;
		size_t temp_used = m_used - dataPos;
		char temp_buffer[temp_used];
		copy(&temp_buffer, dataPos, temp_used);
		assign(&temp_buffer, temp_used);
		return m_used;
	}

	bool copy(char* dataRef) {
		if (dataRef == nullptr)
			return false;
		if (m_used == 0)
			return false;
		memcpy(dataRef, m_buffer, m_used);
		return true;
	}

	bool copy(char* dataRef, size_t dataPos, size_t dataCount) {
		if (dataRef == nullptr)
			return false;
		if (dataPos >= m_used)
			return false;
		if (dataCount == 0)
			return false;
		if ((dataPos + dataCount) > m_used) {
			memcpy(dataRef, &m_buffer[dataPos], (m_used - dataPos));
			memset(&dataRef[m_used - dataPos], 0, (dataCount - (m_used - dataPos)));
		}
		else {
			memcpy(dataRef, &m_buffer[dataPos], dataCount);
		}
		return true;
	}

	char* copy() {
		if (m_used == 0)
			return nullptr;
		char* buffer_copy = new char[m_used];
		memcpy(buffer_copy, m_buffer, m_used);
		return buffer_copy;
	}

	char* copy(size_t dataPos, size_t dataCount) {
		if (dataPos >= m_used)
			return nullptr;
		if (dataCount == 0)
			return nullptr;
		char* buffer_copy = new char[dataCount];
		if ((dataPos + dataCount) > m_used) {
			memcpy(buffer_copy, &m_buffer[dataPos], (m_used - dataPos));
			memset(&buffer_copy[m_used - dataPos], 0, (dataCount - (m_used - dataPos)));
		}
		else {
			memcpy(buffer_copy, &m_buffer[dataPos], dataCount);
		}
		return buffer_copy;
	}

	template<typename T> size_t write(const T& dataValue) {
		if (sizeof(T) > m_free)
			return failed();
		return append_count((const char*)&dataValue, sizeof(T));
	}

	template<typename T> size_t write(const T* dataRef, size_t dataCount) {
		if (dataRef == nullptr)
			return failed();
		if (dataCount == 0)
			return failed();
		if ((sizeof(T) * dataCount) > m_free)
			return failed();
		return append_count((const char*)dataRef, (sizeof(T) * dataCount));
	}

	size_t write_nullterm() {
		if (sizeof(char) > m_free)
			return failed();
		return append_count((const char*)&'\0' sizeof(char));
	}

	size_t write_string(const std::string& dataRef) {
		if (dataRef.length() > m_free)
			return failed();
		return append_count(dataRef.c_str(), dataRef.length());
	}

	// operators
	void operator = (const char* dataRef) {
		assign(dataRef);
	}

	void operator = (const std::string& dataRef) {
		assign(dataRef);
	}

	void operator += (const char* dataRef) {
		append(dataRef);
	}

	void operator += (const std::string& dataRef) {
		append(dataRef);
	}

	void operator << (const char* dataRef) {
		append(dataRef);
	}

	void operator << (const std::string& dataRef) {
		append(dataRef);
	}

	void operator >> (char* dataRef) { // not overrun safe
		copy(dataRef);
	}

	void operator >> (std::string& dataRef) {
		dataRef.append(&m_buffer);
	}

private:
	size_t append_count(const char* dataRef, size_t dataCount) {
		memcpy((&m_buffer[m_used]), dataRef, dataCount);
		m_used += dataCount;
		m_free = m_size - m_used;
		m_last = dataCount;
		return dataCount;
	}

	size_t append_nullterm(const char* dataRef) {
		size_t index = 0;
		for (; dataRef[index] != '\0' && index < m_free; ++index)
			m_buffer[m_used + index] = dataRef[index];
		m_used += index;
		m_free = m_size - m_used;
		m_last = index;
		return index;
	}

	size_t failed() {
		m_last = 0;
		return 0;
	}

	const size_t m_size = size;
	size_t m_used;
	size_t m_free;
	size_t m_last;
	char m_buffer[size + 1];
};

Raw Paste Data