/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef PacketUtilities_h__
#define PacketUtilities_h__
#include "ByteBuffer.h"
#include "Tuples.h"
#include
namespace WorldPackets
{
class InvalidStringValueException : public ByteBufferInvalidValueException
{
public:
InvalidStringValueException(std::string const& value);
std::string const& GetInvalidValue() const { return _value; }
private:
std::string _value;
};
class InvalidUtf8ValueException : public InvalidStringValueException
{
public:
InvalidUtf8ValueException(std::string const& value);
};
class InvalidHyperlinkException : public InvalidStringValueException
{
public:
InvalidHyperlinkException(std::string const& value);
};
class IllegalHyperlinkException : public InvalidStringValueException
{
public:
IllegalHyperlinkException(std::string const& value);
};
namespace Strings
{
struct RawBytes { static bool Validate(std::string const& /*value*/) { return true; } };
template
struct ByteSize { static bool Validate(std::string const& value) { return value.size() <= MaxBytesWithoutNullTerminator; } };
struct Utf8 { static bool Validate(std::string const& value); };
//struct Hyperlinks { static bool Validate(std::string const& value); };
struct NoHyperlinks { static bool Validate(std::string const& value); };
}
/**
* Utility class for automated prevention of invalid strings in client packets
*/
template
class String
{
using ValidatorList = std::conditional_t>::value,
std::tuple, Strings::Utf8, Validators...>,
std::tuple, Validators...>>;
public:
bool empty() const { return _storage.empty(); }
char const* c_str() const { return _storage.c_str(); }
operator std::string_view() const { return _storage; }
operator std::string&() { return _storage; }
operator std::string const&() const { return _storage; }
std::string&& Move() { return std::move(_storage); }
friend ByteBuffer& operator>>(ByteBuffer& data, String& value)
{
value._storage = data.ReadCString(false);
value.Validate();
return data;
}
private:
bool Validate() const
{
return ValidateNth(std::make_index_sequence>{});
}
template
bool ValidateNth(std::index_sequence) const
{
return (std::tuple_element_t::Validate(_storage) && ...);
}
std::string _storage;
};
class PacketArrayMaxCapacityException : public ByteBufferException
{
public:
PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit);
};
/**
* Utility class for automated prevention of loop counter spoofing in client packets
*/
template
class Array
{
typedef std::vector storage_type;
typedef typename storage_type::value_type value_type;
typedef typename storage_type::size_type size_type;
typedef typename storage_type::reference reference;
typedef typename storage_type::const_reference const_reference;
typedef typename storage_type::iterator iterator;
typedef typename storage_type::const_iterator const_iterator;
public:
Array() : _limit(N) { }
Array(size_type limit) : _limit(limit) { }
iterator begin() { return _storage.begin(); }
const_iterator begin() const { return _storage.begin(); }
iterator end() { return _storage.end(); }
const_iterator end() const { return _storage.end(); }
size_type size() const { return _storage.size(); }
bool empty() const { return _storage.empty(); }
reference operator[](size_type i) { return _storage[i]; }
const_reference operator[](size_type i) const { return _storage[i]; }
void resize(size_type newSize)
{
if (newSize > _limit)
{
throw PacketArrayMaxCapacityException(newSize, _limit);
}
_storage.resize(newSize);
}
void reserve(size_type newSize)
{
if (newSize > _limit)
{
throw PacketArrayMaxCapacityException(newSize, _limit);
}
_storage.reserve(newSize);
}
void push_back(value_type const& value)
{
if (_storage.size() >= _limit)
{
throw PacketArrayMaxCapacityException(_storage.size() + 1, _limit);
}
_storage.push_back(value);
}
void push_back(value_type&& value)
{
if (_storage.size() >= _limit)
{
throw PacketArrayMaxCapacityException(_storage.size() + 1, _limit);
}
_storage.push_back(std::forward(value));
}
private:
storage_type _storage;
size_type _limit;
};
void CheckCompactArrayMaskOverflow(std::size_t index, std::size_t limit);
template
class CompactArray
{
public:
CompactArray() : _mask(0) { }
CompactArray(CompactArray const& right)
: _mask(right._mask), _contents(right._contents) { }
CompactArray(CompactArray&& right)
: _mask(right._mask), _contents(std::move(right._contents))
{
right._mask = 0;
}
CompactArray& operator=(CompactArray const& right)
{
_mask = right._mask;
_contents = right._contents;
return *this;
}
CompactArray& operator=(CompactArray&& right)
{
_mask = right._mask;
right._mask = 0;
_contents = std::move(right._contents);
return *this;
}
uint32 GetMask() const { return _mask; }
T const& operator[](std::size_t index) const { return _contents.at(index); }
std::size_t GetSize() const { return _contents.size(); }
void Insert(std::size_t index, T const& value)
{
CheckCompactArrayMaskOverflow(index, sizeof(_mask) * 8);
_mask |= 1 << index;
if (_contents.size() <= index)
{
_contents.resize(index + 1);
}
_contents[index] = value;
}
void Clear()
{
_mask = 0;
_contents.clear();
}
bool operator==(CompactArray const& r) const
{
if (_mask != r._mask)
{
return false;
}
return _contents == r._contents;
}
bool operator!=(CompactArray const& r) const { return !(*this == r); }
private:
uint32 _mask;
std::vector _contents;
};
template
ByteBuffer& operator<<(ByteBuffer& data, CompactArray const& v)
{
uint32 mask = v.GetMask();
data << uint32(mask);
for (std::size_t i = 0; i < v.GetSize(); ++i)
{
if (mask & (1 << i))
{
data << v[i];
}
}
return data;
}
template
ByteBuffer& operator>>(ByteBuffer& data, CompactArray& v)
{
uint32 mask;
data >> mask;
for (std::size_t index = 0; mask != 0; mask >>= 1, ++index)
{
if ((mask & 1) != 0)
{
v.Insert(index, data.read());
}
}
return data;
}
}
#endif // PacketUtilities_h__