PageRenderTime 97ms CodeModel.GetById 16ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 0ms

/src/server/shared/Packets/ByteBuffer.h

https://gitlab.com/tkrokli/TrinityCore_434
C Header | 776 lines | 610 code | 125 blank | 41 comment | 60 complexity | d683a825be72e51caf34d861770ee8bb MD5 | raw file
  1/*
  2 * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
  3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4 *
  5 * This program is free software; you can redistribute it and/or modify it
  6 * under the terms of the GNU General Public License as published by the
  7 * Free Software Foundation; either version 2 of the License, or (at your
  8 * option) any later version.
  9 *
 10 * This program is distributed in the hope that it will be useful, but WITHOUT
 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 13 * more details.
 14 *
 15 * You should have received a copy of the GNU General Public License along
 16 * with this program. If not, see <http://www.gnu.org/licenses/>.
 17 */
 18
 19#ifndef _BYTEBUFFER_H
 20#define _BYTEBUFFER_H
 21
 22#include "Define.h"
 23#include "Errors.h"
 24#include "ByteConverter.h"
 25#include "Util.h"
 26
 27#include <exception>
 28#include <list>
 29#include <map>
 30#include <string>
 31#include <vector>
 32#include <cstring>
 33#include <time.h>
 34#include <cmath>
 35#include <type_traits>
 36#include <boost/asio/buffer.hpp>
 37
 38class MessageBuffer;
 39
 40// Root of ByteBuffer exception hierarchy
 41class ByteBufferException : public std::exception
 42{
 43public:
 44    ~ByteBufferException() throw() { }
 45
 46    char const* what() const throw() override { return msg_.c_str(); }
 47
 48protected:
 49    std::string & message() throw() { return msg_; }
 50
 51private:
 52    std::string msg_;
 53};
 54
 55class ByteBufferPositionException : public ByteBufferException
 56{
 57public:
 58    ByteBufferPositionException(bool add, size_t pos, size_t size, size_t valueSize);
 59
 60    ~ByteBufferPositionException() throw() { }
 61};
 62
 63class ByteBufferSourceException : public ByteBufferException
 64{
 65public:
 66    ByteBufferSourceException(size_t pos, size_t size, size_t valueSize);
 67
 68    ~ByteBufferSourceException() throw() { }
 69};
 70
 71class ByteBuffer
 72{
 73    public:
 74        static size_t const DEFAULT_SIZE = 0x1000;
 75        static uint8 const InitialBitPos = 8;
 76
 77        // constructor
 78        ByteBuffer() : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0)
 79        {
 80            _storage.reserve(DEFAULT_SIZE);
 81        }
 82
 83        ByteBuffer(size_t reserve) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0)
 84        {
 85            _storage.reserve(reserve);
 86        }
 87
 88        ByteBuffer(ByteBuffer&& buf) : _rpos(buf._rpos), _wpos(buf._wpos),
 89            _bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(std::move(buf._storage)) { }
 90
 91        ByteBuffer(ByteBuffer const& right) : _rpos(right._rpos), _wpos(right._wpos),
 92            _bitpos(right._bitpos), _curbitval(right._curbitval), _storage(right._storage) { }
 93
 94        ByteBuffer(MessageBuffer&& buffer);
 95
 96        ByteBuffer& operator=(ByteBuffer const& right)
 97        {
 98            if (this != &right)
 99            {
100                _rpos = right._rpos;
101                _wpos = right._wpos;
102                _bitpos = right._bitpos;
103                _curbitval = right._curbitval;
104                _storage = right._storage;
105            }
106
107            return *this;
108        }
109
110        virtual ~ByteBuffer() { }
111
112        void clear()
113        {
114            _storage.clear();
115            _rpos = _wpos = 0;
116        }
117
118        template <typename T> void append(T value)
119        {
120            static_assert(std::is_fundamental<T>::value, "append(compound)");
121            EndianConvert(value);
122            append((uint8 *)&value, sizeof(value));
123        }
124
125        void FlushBits()
126        {
127            if (_bitpos == 8)
128                return;
129
130            _bitpos = 8;
131
132            append((uint8 *)&_curbitval, sizeof(uint8));
133            _curbitval = 0;
134        }
135
136        bool WriteBit(uint32 bit)
137        {
138            --_bitpos;
139            if (bit)
140                _curbitval |= (1 << (_bitpos));
141
142            if (_bitpos == 0)
143            {
144                _bitpos = 8;
145                append((uint8 *)&_curbitval, sizeof(_curbitval));
146                _curbitval = 0;
147            }
148
149            return (bit != 0);
150        }
151
152        bool ReadBit()
153        {
154            ++_bitpos;
155            if (_bitpos > 7)
156            {
157                _bitpos = 0;
158                _curbitval = read<uint8>();
159            }
160
161            return ((_curbitval >> (7-_bitpos)) & 1) != 0;
162        }
163
164        template <typename T> void WriteBits(T value, size_t bits)
165        {
166            for (int32 i = bits-1; i >= 0; --i)
167                WriteBit((value >> i) & 1);
168        }
169
170        uint32 ReadBits(size_t bits)
171        {
172            uint32 value = 0;
173            for (int32 i = bits-1; i >= 0; --i)
174                if (ReadBit())
175                    value |= (1 << (i));
176
177            return value;
178        }
179
180        // Reads a byte (if needed) in-place
181        void ReadByteSeq(uint8& b)
182        {
183            if (b != 0)
184                b ^= read<uint8>();
185        }
186
187        void WriteByteSeq(uint8 b)
188        {
189            if (b != 0)
190                append<uint8>(b ^ 1);
191        }
192
193        template <typename T> void put(size_t pos, T value)
194        {
195            static_assert(std::is_fundamental<T>::value, "append(compound)");
196            EndianConvert(value);
197            put(pos, (uint8 *)&value, sizeof(value));
198        }
199
200        /**
201          * @name   PutBits
202          * @brief  Places specified amount of bits of value at specified position in packet.
203          *         To ensure all bits are correctly written, only call this method after
204          *         bit flush has been performed
205
206          * @param  pos Position to place the value at, in bits. The entire value must fit in the packet
207          *             It is advised to obtain the position using bitwpos() function.
208
209          * @param  value Data to write.
210          * @param  bitCount Number of bits to store the value on.
211        */
212        template <typename T> void PutBits(size_t pos, T value, uint32 bitCount)
213        {
214            if (!bitCount)
215                throw ByteBufferSourceException((pos + bitCount) / 8, size(), 0);
216
217            if (pos + bitCount > size() * 8)
218                throw ByteBufferPositionException(false, (pos + bitCount) / 8, size(), (bitCount - 1) / 8 + 1);
219
220            for (uint32 i = 0; i < bitCount; ++i)
221            {
222                size_t wp = (pos + i) / 8;
223                size_t bit = (pos + i) % 8;
224                if ((value >> (bitCount - i - 1)) & 1)
225                    _storage[wp] |= 1 << (7 - bit);
226                else
227                    _storage[wp] &= ~(1 << (7 - bit));
228            }
229        }
230
231        ByteBuffer &operator<<(uint8 value)
232        {
233            append<uint8>(value);
234            return *this;
235        }
236
237        ByteBuffer &operator<<(uint16 value)
238        {
239            append<uint16>(value);
240            return *this;
241        }
242
243        ByteBuffer &operator<<(uint32 value)
244        {
245            append<uint32>(value);
246            return *this;
247        }
248
249        ByteBuffer &operator<<(uint64 value)
250        {
251            append<uint64>(value);
252            return *this;
253        }
254
255        // signed as in 2e complement
256        ByteBuffer &operator<<(int8 value)
257        {
258            append<int8>(value);
259            return *this;
260        }
261
262        ByteBuffer &operator<<(int16 value)
263        {
264            append<int16>(value);
265            return *this;
266        }
267
268        ByteBuffer &operator<<(int32 value)
269        {
270            append<int32>(value);
271            return *this;
272        }
273
274        ByteBuffer &operator<<(int64 value)
275        {
276            append<int64>(value);
277            return *this;
278        }
279
280        // floating points
281        ByteBuffer &operator<<(float value)
282        {
283            append<float>(value);
284            return *this;
285        }
286
287        ByteBuffer &operator<<(double value)
288        {
289            append<double>(value);
290            return *this;
291        }
292
293        ByteBuffer &operator<<(const std::string &value)
294        {
295            if (size_t len = value.length())
296                append((uint8 const*)value.c_str(), len);
297            append((uint8)0);
298            return *this;
299        }
300
301        ByteBuffer &operator<<(const char *str)
302        {
303            if (size_t len = (str ? strlen(str) : 0))
304                append((uint8 const*)str, len);
305            append((uint8)0);
306            return *this;
307        }
308
309        ByteBuffer &operator>>(bool &value)
310        {
311            value = read<char>() > 0 ? true : false;
312            return *this;
313        }
314
315        ByteBuffer &operator>>(uint8 &value)
316        {
317            value = read<uint8>();
318            return *this;
319        }
320
321        ByteBuffer &operator>>(uint16 &value)
322        {
323            value = read<uint16>();
324            return *this;
325        }
326
327        ByteBuffer &operator>>(uint32 &value)
328        {
329            value = read<uint32>();
330            return *this;
331        }
332
333        ByteBuffer &operator>>(uint64 &value)
334        {
335            value = read<uint64>();
336            return *this;
337        }
338
339        //signed as in 2e complement
340        ByteBuffer &operator>>(int8 &value)
341        {
342            value = read<int8>();
343            return *this;
344        }
345
346        ByteBuffer &operator>>(int16 &value)
347        {
348            value = read<int16>();
349            return *this;
350        }
351
352        ByteBuffer &operator>>(int32 &value)
353        {
354            value = read<int32>();
355            return *this;
356        }
357
358        ByteBuffer &operator>>(int64 &value)
359        {
360            value = read<int64>();
361            return *this;
362        }
363
364        ByteBuffer &operator>>(float &value)
365        {
366            value = read<float>();
367            if (!std::isfinite(value))
368                throw ByteBufferException();
369            return *this;
370        }
371
372        ByteBuffer &operator>>(double &value)
373        {
374            value = read<double>();
375            if (!std::isfinite(value))
376                throw ByteBufferException();
377            return *this;
378        }
379
380        ByteBuffer &operator>>(std::string& value)
381        {
382            value.clear();
383            while (rpos() < size())                         // prevent crash at wrong string format in packet
384            {
385                char c = read<char>();
386                if (c == 0)
387                    break;
388                value += c;
389            }
390            return *this;
391        }
392
393        uint8& operator[](size_t const pos)
394        {
395            if (pos >= size())
396                throw ByteBufferPositionException(false, pos, 1, size());
397            return _storage[pos];
398        }
399
400        uint8 const& operator[](size_t const pos) const
401        {
402            if (pos >= size())
403                throw ByteBufferPositionException(false, pos, 1, size());
404            return _storage[pos];
405        }
406
407        size_t rpos() const { return _rpos; }
408
409        size_t rpos(size_t rpos_)
410        {
411            _rpos = rpos_;
412            return _rpos;
413        }
414
415        void rfinish()
416        {
417            _rpos = wpos();
418        }
419
420        size_t wpos() const { return _wpos; }
421
422        size_t wpos(size_t wpos_)
423        {
424            _wpos = wpos_;
425            return _wpos;
426        }
427
428        /// Returns position of last written bit
429        size_t bitwpos() const { return _wpos * 8 + 8 - _bitpos; }
430
431        size_t bitwpos(size_t newPos)
432        {
433            _wpos = newPos / 8;
434            _bitpos = 8 - (newPos % 8);
435            return _wpos * 8 + 8 - _bitpos;
436        }
437
438        template<typename T>
439        void read_skip() { read_skip(sizeof(T)); }
440
441        void read_skip(size_t skip)
442        {
443            if (_rpos + skip > size())
444                throw ByteBufferPositionException(false, _rpos, skip, size());
445            _rpos += skip;
446        }
447
448        template <typename T> T read()
449        {
450            T r = read<T>(_rpos);
451            _rpos += sizeof(T);
452            return r;
453        }
454
455        template <typename T> T read(size_t pos) const
456        {
457            if (pos + sizeof(T) > size())
458                throw ByteBufferPositionException(false, pos, sizeof(T), size());
459            T val = *((T const*)&_storage[pos]);
460            EndianConvert(val);
461            return val;
462        }
463
464        void read(uint8 *dest, size_t len)
465        {
466            if (_rpos  + len > size())
467               throw ByteBufferPositionException(false, _rpos, len, size());
468            std::memcpy(dest, &_storage[_rpos], len);
469            _rpos += len;
470        }
471
472        void readPackGUID(uint64& guid)
473        {
474            if (rpos() + 1 > size())
475                throw ByteBufferPositionException(false, _rpos, 1, size());
476
477            guid = 0;
478
479            uint8 guidmark = 0;
480            (*this) >> guidmark;
481
482            for (int i = 0; i < 8; ++i)
483            {
484                if (guidmark & (uint8(1) << i))
485                {
486                    if (rpos() + 1 > size())
487                        throw ByteBufferPositionException(false, _rpos, 1, size());
488
489                    uint8 bit;
490                    (*this) >> bit;
491                    guid |= (uint64(bit) << (i * 8));
492                }
493            }
494        }
495
496        std::string ReadString(uint32 length)
497        {
498            if (!length)
499                return std::string();
500            char* buffer = new char[length + 1]();
501            read((uint8*)buffer, length);
502            std::string retval = buffer;
503            delete[] buffer;
504            return retval;
505        }
506
507        //! Method for writing strings that have their length sent separately in packet
508        //! without null-terminating the string
509        void WriteString(std::string const& str)
510        {
511            if (size_t len = str.length())
512                append(str.c_str(), len);
513        }
514
515        uint32 ReadPackedTime()
516        {
517            uint32 packedDate = read<uint32>();
518            tm lt = tm();
519
520            lt.tm_min = packedDate & 0x3F;
521            lt.tm_hour = (packedDate >> 6) & 0x1F;
522            //lt.tm_wday = (packedDate >> 11) & 7;
523            lt.tm_mday = ((packedDate >> 14) & 0x3F) + 1;
524            lt.tm_mon = (packedDate >> 20) & 0xF;
525            lt.tm_year = ((packedDate >> 24) & 0x1F) + 100;
526
527            return uint32(mktime(&lt));
528        }
529
530        ByteBuffer& ReadPackedTime(uint32& time)
531        {
532            time = ReadPackedTime();
533            return *this;
534        }
535
536        uint8* contents()
537        {
538            if (_storage.empty())
539                throw ByteBufferException();
540            return _storage.data();
541        }
542
543        uint8 const* contents() const
544        {
545            if (_storage.empty())
546                throw ByteBufferException();
547            return _storage.data();
548        }
549
550        size_t size() const { return _storage.size(); }
551        bool empty() const { return _storage.empty(); }
552
553        void resize(size_t newsize)
554        {
555            _storage.resize(newsize, 0);
556            _rpos = 0;
557            _wpos = size();
558        }
559
560        void reserve(size_t ressize)
561        {
562            if (ressize > size())
563                _storage.reserve(ressize);
564        }
565
566        void append(const char *src, size_t cnt)
567        {
568            return append((const uint8 *)src, cnt);
569        }
570
571        template<class T> void append(const T *src, size_t cnt)
572        {
573            return append((const uint8 *)src, cnt * sizeof(T));
574        }
575
576        void append(const uint8 *src, size_t cnt)
577        {
578            if (!cnt)
579                throw ByteBufferSourceException(_wpos, size(), cnt);
580
581            if (!src)
582                throw ByteBufferSourceException(_wpos, size(), cnt);
583
584            ASSERT(size() < 10000000);
585
586            FlushBits();
587
588            if (_storage.size() < _wpos + cnt)
589                _storage.resize(_wpos + cnt);
590            std::memcpy(&_storage[_wpos], src, cnt);
591            _wpos += cnt;
592        }
593
594        void append(const ByteBuffer& buffer)
595        {
596            if (buffer.wpos())
597                append(buffer.contents(), buffer.wpos());
598        }
599
600        // can be used in SMSG_MONSTER_MOVE opcode
601        void appendPackXYZ(float x, float y, float z)
602        {
603            uint32 packed = 0;
604            packed |= ((int)(x / 0.25f) & 0x7FF);
605            packed |= ((int)(y / 0.25f) & 0x7FF) << 11;
606            packed |= ((int)(z / 0.25f) & 0x3FF) << 22;
607            *this << packed;
608        }
609
610        void appendPackGUID(uint64 guid)
611        {
612            uint8 packGUID[8+1];
613            packGUID[0] = 0;
614            size_t size = 1;
615            for (uint8 i = 0;guid != 0;++i)
616            {
617                if (guid & 0xFF)
618                {
619                    packGUID[0] |= uint8(1 << i);
620                    packGUID[size] =  uint8(guid & 0xFF);
621                    ++size;
622                }
623
624                guid >>= 8;
625            }
626            append(packGUID, size);
627        }
628
629        void AppendPackedTime(time_t time)
630        {
631            tm lt;
632            localtime_r(&time, &lt);
633            append<uint32>((lt.tm_year - 100) << 24 | lt.tm_mon  << 20 | (lt.tm_mday - 1) << 14 | lt.tm_wday << 11 | lt.tm_hour << 6 | lt.tm_min);
634        }
635
636        void put(size_t pos, const uint8 *src, size_t cnt)
637        {
638            if (pos + cnt > size())
639                throw ByteBufferPositionException(true, pos, cnt, size());
640
641            if (!src)
642                throw ByteBufferSourceException(_wpos, size(), cnt);
643
644            std::memcpy(&_storage[pos], src, cnt);
645        }
646
647        void print_storage() const;
648
649        void textlike() const;
650
651        void hexlike() const;
652
653    protected:
654        size_t _rpos, _wpos, _bitpos;
655        uint8 _curbitval;
656        std::vector<uint8> _storage;
657};
658
659template <typename T>
660inline ByteBuffer &operator<<(ByteBuffer &b, std::vector<T> v)
661{
662    b << (uint32)v.size();
663    for (typename std::vector<T>::iterator i = v.begin(); i != v.end(); ++i)
664    {
665        b << *i;
666    }
667    return b;
668}
669
670template <typename T>
671inline ByteBuffer &operator>>(ByteBuffer &b, std::vector<T> &v)
672{
673    uint32 vsize;
674    b >> vsize;
675    v.clear();
676    while (vsize--)
677    {
678        T t;
679        b >> t;
680        v.push_back(t);
681    }
682    return b;
683}
684
685template <typename T>
686inline ByteBuffer &operator<<(ByteBuffer &b, std::list<T> v)
687{
688    b << (uint32)v.size();
689    for (typename std::list<T>::iterator i = v.begin(); i != v.end(); ++i)
690    {
691        b << *i;
692    }
693    return b;
694}
695
696template <typename T>
697inline ByteBuffer &operator>>(ByteBuffer &b, std::list<T> &v)
698{
699    uint32 vsize;
700    b >> vsize;
701    v.clear();
702    while (vsize--)
703    {
704        T t;
705        b >> t;
706        v.push_back(t);
707    }
708    return b;
709}
710
711template <typename K, typename V>
712inline ByteBuffer &operator<<(ByteBuffer &b, std::map<K, V> &m)
713{
714    b << (uint32)m.size();
715    for (typename std::map<K, V>::iterator i = m.begin(); i != m.end(); ++i)
716    {
717        b << i->first << i->second;
718    }
719    return b;
720}
721
722template <typename K, typename V>
723inline ByteBuffer &operator>>(ByteBuffer &b, std::map<K, V> &m)
724{
725    uint32 msize;
726    b >> msize;
727    m.clear();
728    while (msize--)
729    {
730        K k;
731        V v;
732        b >> k >> v;
733        m.insert(make_pair(k, v));
734    }
735    return b;
736}
737
738/// @todo Make a ByteBuffer.cpp and move all this inlining to it.
739template<> inline std::string ByteBuffer::read<std::string>()
740{
741    std::string tmp;
742    *this >> tmp;
743    return tmp;
744}
745
746template<>
747inline void ByteBuffer::read_skip<char*>()
748{
749    std::string temp;
750    *this >> temp;
751}
752
753template<>
754inline void ByteBuffer::read_skip<char const*>()
755{
756    read_skip<char*>();
757}
758
759template<>
760inline void ByteBuffer::read_skip<std::string>()
761{
762    read_skip<char*>();
763}
764
765namespace boost
766{
767    namespace asio
768    {
769        inline const_buffers_1 buffer(ByteBuffer const& packet)
770        {
771            return buffer(packet.contents(), packet.size());
772        }
773    }
774}
775
776#endif