⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stream.h

📁 C++ patterns设计模式
💻 H
字号:
////////////////////////////////////////////////////////////////////////////////
// 基本的流处理
////////////////////////////////////////////////////////////////////////////////
// Author      : 黎达文
// Description : 基本的流编码解码
//
// Version     : 1.3
//
// Standard include files : 
//
// Start Date  : 2003年4月3日
//
// Change Log  : reference the end of this file
////////////////////////////////////////////////////////////////////////////////

#ifndef INCLUDED_STREAM_H
#define INCLUDED_STREAM_H

#if defined(HAS_PRAGMA_ONCE)
#pragma PRAGMA_ONCE_DECLARE
#endif

#include "type_def.h"
#include "patterns/util/util.h"    // access s_strEmpty

//CTBaseBuffer support a continuouse and auto resize buffer.
//it can convert to a base "char *" type by calling tellp method
//we use the std::vector<u8> as this CTBaseBuffer.
//CTBaseBuffer is the main container

namespace protocol
{
	class BaseStream
	{
        typedef std::vector<char > StreamContainer;
	public:
		explicit BaseStream()
		{
			reset();
		}

		//integer encode routine
		inline void enc32(u32 value)
		{
			enc8(u8(value >> 24));
			enc8(u8(value >> 16));
			enc8(u8(value >> 8));
			enc8(u8(value));
		}
		inline void enc16(u16 value)
		{
			enc8(u8(value >> 8));
			enc8(u8(value));
		}
		inline void enc8 (u8  value)
		{
			m_container.push_back(value);
		}

		//string encode routine
		void encFixedString(const std::string& str, 
			size_t fixedLen, 
			u8 fillFlag = '\0');

		void encVmaxString( const std::string& str, 
			size_t maxLen, 
			u8 endFlag = '\0');

		void encString(const std::string& str);
		void encStream(const BaseStream& stream);

		/// integer decode routine
		/**
		 * the follow dec method must use u8 type conversion, 
		 * coz the base type of stream container is "char"
		 * if no type conversion, the shift action will not correct
		 */

		inline bool dec32(u32& value)
		{
			if(left() < sizeof(u32))
				return false;

			u32 accumulator = (u8)m_container[m_offset++];		// get the first byte
			accumulator = (accumulator << 8) | (u8)m_container[m_offset++];	// second
			accumulator = (accumulator << 8) | (u8)m_container[m_offset++]; // ...
			accumulator = (accumulator << 8) | (u8)m_container[m_offset++]; // ...
			value = accumulator;
			return true;
		}

		inline bool dec16(u16& value)
		{
			if(left() < sizeof(u16))
				return false;

			u16 accumulator = (u8)m_container[m_offset++];		//get the first byte;
			accumulator = (accumulator << 8) | (u8)m_container[m_offset++];	//second
			value = accumulator;
			return true;
		}

		inline bool dec8 (u8 & value)
		{
			if(left() < sizeof(u8))
				return false;

			value = (u8)m_container[m_offset++];
			return true;
		}

		bool decFixedString(std::string& str, size_t fixedLen);
		bool decVmaxString (std::string& str, size_t maxLen, u8 endFlag = '\0');
		bool decString     (std::string& str);
        bool decStream     (BaseStream& stream, size_t length);

        template<class InputIterator>
            void assign(InputIterator first, InputIterator last)
        {
            m_container.assign(first, last);
        }

        BaseStream& operator+=(const BaseStream& other)
        {
            m_container.insert(end(), other.begin(), other.end());
            return *this;
        }
        bool operator == (const BaseStream& other) const
        {
            return m_container == other.m_container;
        }
        bool operator != (const BaseStream& other) const
        {
            return !(*this == other);
        }
		/// how many buffer left when decoding
		size_t left() const
		{
			return size() - m_offset;
		}
        /// decoder offset position
		size_t offset() const
		{
			return m_offset;
		}
        /**
		 * reset the decode offset
         * default parameter means reset to begin position
         * positive number means advance the position if it can advance
         * if advance overflow then offset set to the last position (not the just over last position)
         * negative number means back off the position if it can back off
         * if back off underflow then offset set to zero
		 */
		void   reset(int offset = 0)
		{
            if(offset == 0)
            {
                m_offset = 0;
            }
            else
            {
                m_offset += offset;
            }
            //check overflow or underflow
            if(m_offset<0)
            {
                m_offset = 0;
            }
            else if(m_offset > size())
            {
                m_offset = size();
            }
		}

        /// clear the stream buffer, not free the memory!
        void   clear()
        {
            m_container.clear();
        }

        /// free the stream buffer's memory
        void   free()
        {
            reset();
			StreamContainer().swap(m_container);
            // m_container.swap(StreamContainer());
        }

		/// return the current buffer position, read only!
		const char *getBuffer(size_t offset = 0) const
		{
			if(offset>=0 && offset < m_container.size())
				return &m_container[offset];
			else
				return stk::s_strEmpty.c_str();
		}

		/**
		 * return the buffer which can be write directly, 
		 * must call resize method to alloc enough buffer!
		 */
		char *getWriteBuffer(size_t offset = 0)
		{
			assert(offset>=0 && offset <= m_container.size());
			return &m_container[offset];
		}

        //make some STL algorithm interface
        size_t size() const
        {
            return m_container.size();
        }
		void resize(StreamContainer::size_type newSize)
		{
			m_container.resize(newSize);
		}
		void reserve(StreamContainer::size_type count)
		{
			m_container.reserve(count);
		}
		bool empty() const
		{
			return m_container.empty();
		}

        StreamContainer::const_iterator begin() const
        {
            return m_container.begin();
        }
		/// current decode position
        StreamContainer::const_iterator current() const
        {
            return m_container.begin()+m_offset;
        }
        StreamContainer::const_iterator end() const
        {
            return m_container.end();
        }
        StreamContainer::iterator begin()
        {
            return m_container.begin();
        }
        StreamContainer::iterator current()
        {
            return m_container.begin()+m_offset;
        }
        StreamContainer::iterator end()
        {
            return m_container.end();
        }
        void swap(BaseStream& right)
        {
			std::swap(m_offset, right.m_offset);
            m_container.swap(right.m_container);
        }
	protected:
        StreamContainer m_container;
        size_t          m_offset;		//indicate the decode position
	};

	/// change the byte order(16bit)
	inline u16 changeOrder(u16 org)
	{
		u16 result = (org>>8) & 0xFF;
		result |= (org&0xFF) << 8;
		return result;
	}
	/// change the byte order(32bit)
	inline u32 changeOrder(u32 org)
	{
		u16 high16 = (u16)( (org>>16) && 0xFFFF );
		u16 low16  = (u16)( org&0xFFFF );
		high16 = changeOrder(high16);
		low16  = changeOrder(low16);
		return (low16<<16 | high16);
	}
};

/// for the old name
namespace ptl = protocol;

/// define suntek name format
typedef protocol::BaseStream CTBaseStream;

//////////////////////////////////////////////////////////////////////////
// Change Log:
// 20021231 by darkay
//     add dec_buf_v and dec_str_v method for variable length string with ending flag
//     and enc_buf and enc_str with no size parameter, it encode the string while not end of \0'; 
// 20030105 by darkay
//     modify dec_str method, move m_offset++ from the "while condition" into "while scope"
// 20030223 by darkay li
//     add compatible for VC6, coz it's insert function of vector not support general parameter
//     so, I must do some cast.
// Darkay Li [5/22/2003]
//  add namespace protocol, and macro for suntek name format
// 2003年6月27日 by Darkay Li
//  remove derive from StreamContianer, let StreamContianer as data members
//  add the STL's iterator interface like begin(), end() and current()
//  add encStream/decStream method
//  implement decString method.
//  add default ctor parameter to init stream minimal size for speed up
// 2003年12月4日 by Darkay Li
//  1. modify the stream container from vector<u8> to vector<char>, 
//     this modification make it convert to char * easyly
//  2. add another getBuffer interface, it return non-const char * pointer, 
//     it support such usage "resize stream to enough size, and use the stream buffer directly" now
//     it's useful when receiving data from socket.
//  3. remove "CTBaseStream" definition
//  4. add global function changeOrder to change byte order
//  5. make much method "inline"
// 2004年3月24日 by Darkay Li
//  1. change char *getBuffer(size_t offset = 0) to
//     char *getWriteBuffer(size_t offset = 0)
//     for more clear mean interface name!
// 2004年12月13日 by Darkay Li
//	1. bug fix for method changeOrder(), it's a stupid coding mistake.
//		u16 high16 = (u16)( (org>16) && 0xFFFF );
//		==>
//		u16 high16 = (u16)( (org>>16) && 0xFFFF );
//	2. bug fix for method swap(), missed swap m_offset
//////////////////////////////////////////////////////////////////////////

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -