/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * 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, either version 3 of the License, or * 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 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 _BYTEBUFFER_H #define _BYTEBUFFER_H #include "Common.h" #include "WoWGuid.h" #include "LocationVector.h" class SERVER_DECL ByteBuffer { public: class error { }; const static size_t DEFAULT_SIZE = 0x1000; ByteBuffer(): _rpos(0), _wpos(0) { _storage.reserve(DEFAULT_SIZE); } ByteBuffer(size_t res): _rpos(0), _wpos(0) { _storage.reserve(res); } ByteBuffer(const ByteBuffer &buf): _rpos(buf._rpos), _wpos(buf._wpos), _storage(buf._storage) { } virtual ~ByteBuffer() {} void clear() { _storage.clear(); _rpos = _wpos = 0; } //template void insert(size_t pos, T value) { // insert(pos, (uint8 *)&value, sizeof(value)); //} template void append(T value) { append((uint8 *)&value, sizeof(value)); } template void put(size_t pos,T value) { put(pos,(uint8 *)&value,sizeof(value)); } // stream like operators for storing data ByteBuffer &operator<<(bool value) { append((char)value); return *this; } // unsigned ByteBuffer &operator<<(uint8 value) { append(value); return *this; } ByteBuffer &operator<<(uint16 value) { #ifdef USING_BIG_ENDIAN append(swap16(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(uint32 value) { #ifdef USING_BIG_ENDIAN append(swap32(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(uint64 value) { #ifdef USING_BIG_ENDIAN append(swap64(value)); #else append(value); #endif return *this; } // signed as in 2e complement ByteBuffer &operator<<(int8 value) { append(value); return *this; } ByteBuffer &operator<<(int16 value) { #ifdef USING_BIG_ENDIAN append(swap16(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(int32 value) { #ifdef USING_BIG_ENDIAN append(swap32(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(int64 value) { #ifdef USING_BIG_ENDIAN append(swap64(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(float value) { #ifdef USING_BIG_ENDIAN append(swapfloat(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(double value) { #ifdef USING_BIG_ENDIAN append(swapdouble(value)); #else append(value); #endif return *this; } ByteBuffer &operator<<(const std::string &value) { append((uint8 *)value.c_str(), value.length()); append((uint8)0); return *this; } ByteBuffer &operator<<(const char *str) { append((uint8 *)str, strlen(str)); append((uint8)0); return *this; } ByteBuffer &operator<<(const WoWGuid &value) { append(value.GetNewGuidMask()); append((uint8 *)value.GetNewGuid(), value.GetNewGuidLen()); return *this; } // stream like operators for reading data ByteBuffer &operator>>(bool &value) { value = read() > 0 ? true : false; return *this; } //unsigned ByteBuffer &operator>>(uint8 &value) { value = read(); return *this; } ByteBuffer &operator>>(uint16 &value) { #ifdef USING_BIG_ENDIAN value = swap16(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(uint32 &value) { #ifdef USING_BIG_ENDIAN value = swap32(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(uint64 &value) { #ifdef USING_BIG_ENDIAN value = swap64(read()); #else value = read(); #endif return *this; } //signed as in 2e complement ByteBuffer &operator>>(int8 &value) { value = read(); return *this; } ByteBuffer &operator>>(int16 &value) { #ifdef USING_BIG_ENDIAN value = swap16(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(int32 &value) { #ifdef USING_BIG_ENDIAN value = swap32(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(int64 &value) { #ifdef USING_BIG_ENDIAN value = swap64(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(float &value) { #ifdef USING_BIG_ENDIAN value = swapfloat(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(double &value) { #ifdef USING_BIG_ENDIAN value = swapdouble(read()); #else value = read(); #endif return *this; } ByteBuffer &operator>>(std::string& value) { value.clear(); while (true) { char c=read(); if (c==0) break; value+=c; } return *this; } //! Only does X,Y,Z! ByteBuffer & operator << (const LocationVector & vec) { #ifdef USING_BIG_ENDIAN append(swapfloat(vec.x)); append(swapfloat(vec.y)); append(swapfloat(vec.z)); #else append(vec.x); append(vec.y); append(vec.z); #endif return *this; } //! Only does X,Y,Z! ByteBuffer & operator >> (LocationVector & vec) { #ifdef USING_BIG_ENDIAN vec.x = swapfloat(read()); vec.y = swapfloat(read()); vec.z = swapfloat(read()); #else vec.x = read(); vec.y = read(); vec.z = read(); #endif return * this; } ByteBuffer &operator>>(WoWGuid &value) { uint8 field, mask = read(); value.Init((uint8)mask); for(int i = 0; i < BitCount8(mask); i++) { field = read(); value.AppendField(field); } return *this; } uint8 operator[](size_t pos) { return read(pos); } size_t rpos() { return _rpos; }; size_t rpos(size_t rpos) { _rpos = rpos; return _rpos; }; size_t wpos() { return _wpos; } size_t wpos(size_t wpos) { _wpos = wpos; return _wpos; } template T read() { T r=read(_rpos); _rpos += sizeof(T); return r; }; template T read(size_t pos) const { //ASSERT(pos + sizeof(T) <= size()); if(pos + sizeof(T) > size()) { return (T)0; } else { return *((T*)&_storage[pos]); } } void read(uint8 *dest, size_t len) { if (_rpos + len <= size()) { memcpy(dest, &_storage[_rpos], len); } else { //throw error(); memset(dest, 0, len); } _rpos += len; } const uint8 *contents() const { return &_storage[0]; }; inline size_t size() const { return _storage.size(); }; // one should never use resize probably void resize(size_t newsize) { _storage.resize(newsize); _rpos = 0; _wpos = size(); }; void reserve(size_t ressize) { if (ressize > size()) _storage.reserve(ressize); }; // appending to the end of buffer void append(const std::string& str) { append((uint8 *)str.c_str(),str.size() + 1); } void append(const char *src, size_t cnt) { return append((const uint8 *)src, cnt); } void append(const uint8 *src, size_t cnt) { if (!cnt) return; // noone should even need uint8buffer longer than 10mb // if you DO need, think about it // then think some more // then use something else // -- qz ASSERT(size() < 10000000); if (_storage.size() < _wpos + cnt) _storage.resize(_wpos + cnt); memcpy(&_storage[_wpos], src, cnt); _wpos += cnt; } void append(const ByteBuffer& buffer) { if(buffer.size() > 0) append(buffer.contents(),buffer.size()); } void put(size_t pos, const uint8 *src, size_t cnt) { ASSERT(pos + cnt <= size()); memcpy(&_storage[pos], src, cnt); } //void insert(size_t pos, const uint8 *src, size_t cnt) { // std::copy(src, src + cnt, inserter(_storage, _storage.begin() + pos)); //} void hexlike() { uint32 j = 1, k = 1; printf("STORAGE_SIZE: %u\n", size() ); for(uint32 i = 0; i < size(); i++) { if ((i == (j*8)) && ((i != (k*16)))) { if (read(i) < 0x0F) { printf("| 0%X ", read(i) ); } else { printf("| %X ", read(i) ); } j++; } else if (i == (k*16)) { rpos(rpos()-16); // move read pointer 16 places back printf(" | "); // write split char for (int x = 0; x < 16; x++) { printf("%c", read(i-16 + x) ); } if (read(i) < 0x0F) { printf("\n0%X ", read(i) ); } else { printf("\n%X ", read(i) ); } k++; j++; } else { if (read(i) < 0x0F) { printf("0%X ", read(i) ); } else { printf("%X ", read(i) ); } } } printf("\n"); } inline void reverse() { std::reverse(_storage.begin(), _storage.end()); } protected: // read and write positions size_t _rpos, _wpos; std::vector _storage; }; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// template ByteBuffer &operator<<(ByteBuffer &b, std::vector v) { b << (uint32)v.size(); for (typename std::vector::iterator i = v.begin(); i != v.end(); i++) { b << *i; } return b; } template ByteBuffer &operator>>(ByteBuffer &b, std::vector &v) { uint32 vsize; b >> vsize; v.clear(); while(vsize--) { T t; b >> t; v.push_back(t); } return b; } template ByteBuffer &operator<<(ByteBuffer &b, std::list v) { b << (uint32)v.size(); for (typename std::list::iterator i = v.begin(); i != v.end(); i++) { b << *i; } return b; } template ByteBuffer &operator>>(ByteBuffer &b, std::list &v) { uint32 vsize; b >> vsize; v.clear(); while(vsize--) { T t; b >> t; v.push_back(t); } return b; } template ByteBuffer &operator<<(ByteBuffer &b, std::map &m) { b << (uint32)m.size(); for (typename std::map::iterator i = m.begin(); i != m.end(); i++) { b << i->first << i->second; } return b; } template ByteBuffer &operator>>(ByteBuffer &b, std::map &m) { uint32 msize; b >> msize; m.clear(); while(msize--) { K k; V v; b >> k >> v; m.insert(make_pair(k, v)); } return b; } #endif