/******************************************************************************/ /* */ /* ! N O T I C E ! N O T I C E ! N O T I C E ! N O T I C E ! */ /* */ /* ©1998 Sierra On-Line, Inc. All Rights Reserved. */ /* U.S. and foreign patents pending. */ /* */ /* THIS SOFTWARE BELONGS TO */ /* Sierra On-Line, Inc. */ /* IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE DIVULGED OR USED */ /* BY PARTIES WHO HAVE NOT RECEIVED WRITTEN AUTHORIZATION FROM */ /* Sierra On-Line, Inc. */ /* 3380 146th Place SE, Suite 300 */ /* Bellevue, WA 98007-6472 */ /* 206 649-9800 */ /* */ /* Federal law provides severe civil penalties for */ /* misuse or violation of trade secrets. */ /* */ /******************************************************************************/ // TMessage.h: // ////////////////////////////////////////////////////////////////////// // 2/12/98 Greg Hoglund, adding new message classes, TRaw, TData, and TMessage // including reference counting #ifndef H_TMessage #define H_TMessage #include "common/won.h" #include "msg/HeaderTypes.h" namespace WONMsg { // Message class types enum MessageClass { eTMessage, eMiniMessage, eSmallMessage, eLargeMessage }; // TRawData // Stores a contiguous buffer and provides methods for appending and removing // data from this buffer. TRawData is nested within TRawMsg and is not meant // to be used alone. Access to this class is via TRawMsg. // -------------------------------------------------------------------------- class TRawData { private: friend class TRawMsg; // *NOTE* Interlocked operations are used on this member, and it must be // 32-bit aligned. Change the byte alignment of the compiler at your own risk! long mRefCount; // reference count int mChunkMult; // Chunking multiplier unsigned char* mDataP; // Data Buffer unsigned long mDataLen; // Data buffer length (total) mutable unsigned char* mReadPtrP; // Buffer read pointer unsigned char* mWritePtrP; // Buffer write pointer mutable string mStrBuf; // Buffer for Read string mutable wstring mWStrBuf; // Buffer for read WString TRawData(const TRawData& theMsgR); //Only TRawMsg can copy // Validate length before a read // May throw BadMsgException void CheckLength(unsigned long theLen) const; //Disable assignment TRawData& operator =(const TRawData& theMsgR); //prevent assignment public: TRawData(); explicit TRawData(unsigned long theDataLen, const void *theData=NULL); ~TRawData(); void * AllocateNewBuffer(unsigned long theSize); void * AddAllocate(unsigned long nNewBytes, bool chunkAlloc, bool doDumbCheck = true); unsigned long GetDataLen() const; unsigned long GetBufferLen() const { return mDataLen; } void AppendLong(unsigned long theLong); void AppendShort(unsigned short theShort); void AppendByte(unsigned char theByte); void AppendBytes(long theNumBytes, const void* theBytesP, bool chunkAlloc = true, bool doDumbCheck = true); void Append_PW_STRING(const wstring& theString); void Append_PA_STRING(const string& theString); void ResetBuffer(void); void ResetReadPointer(void) const { mReadPtrP = mDataP; } void ResetWritePointer(void) { mWritePtrP = mDataP; } unsigned long BytesLeftToRead(void) const; void SkipWritePtrAhead(unsigned long theNumBytes); // The following two methods return ref to internal buffer that is overwritten // on each call to that method // These two methods are OBSOLETE, use ReadString and ReadWString instead! const wstring& Read_PW_STRING() const; const string& Read_PA_STRING() const; void ReadWString(std::wstring& theBufR) const; void ReadString(std::string& theBufR) const; unsigned long ReadLong() const; unsigned short ReadShort() const; unsigned char ReadByte() const; const void* ReadBytes(long theNumBytes) const; const void* PeekBytes(long theNumBytes) const; }; // TRawMsg // Provides access to a contiguous buffer in memory that represents // a data packet. The actual data is referenced. Use the Duplicate() method // to create an exclusive copy of the data. // Pack() and Unpack() are meant to access the memory buffer and append or remove // data fields as needed. Override and implement as needed. // ------------------------------------------------------------------------------ class TRawMsg { public: TRawMsg(); TRawMsg(unsigned long theDataLen, const void *theData=NULL); TRawMsg(const TRawMsg& Rmsg); virtual ~TRawMsg(); TRawMsg& operator= (const TRawMsg&); virtual TRawMsg * Duplicate() const; virtual void Unpack(); virtual void * Pack(); const void * GetDataPtr() const; void * GetDataPtr(); const void * GetWritePtr() const { return rep->mWritePtrP; } void * GetWritePtr() { return rep->mWritePtrP; } unsigned long GetDataLen() const { return rep->GetDataLen(); } unsigned long GetBufferLen() const { return rep->GetBufferLen(); } // Buffering methods void * AllocateNewBuffer(unsigned long theSize) { CopyOnWrite(); return rep->AllocateNewBuffer(theSize); } void * AddAllocate(unsigned long nNewBytes) { CopyOnWrite(); return rep->AddAllocate(nNewBytes, false); } void AppendLong(unsigned long theLong) { CopyOnWrite(); rep->AppendLong(theLong); } void AppendShort(unsigned short theShort) { CopyOnWrite(); rep->AppendShort(theShort); } void AppendByte(unsigned char theByte) { CopyOnWrite(); rep->AppendByte(theByte); } void AppendBytes(long theNumBytes, const void* theBytesP, bool chunkAlloc = true, bool doDumbCheck = true) { CopyOnWrite(); rep->AppendBytes(theNumBytes, theBytesP, chunkAlloc, doDumbCheck); } void Append_PW_STRING(const wstring& theString) { CopyOnWrite(); rep->Append_PW_STRING(theString); } void Append_PA_STRING(const string& theString) { CopyOnWrite(); rep->Append_PA_STRING(theString); } void ResetBuffer(void) { CopyOnWrite(); rep->ResetBuffer(); } void SkipWritePtrAhead(unsigned long theNumBytes) { rep->SkipWritePtrAhead(theNumBytes); } void ResetReadPointer(void) const { rep->ResetReadPointer(); } void ResetWritePointer(void) { rep->ResetWritePointer(); } unsigned long BytesLeftToRead(void) const { return rep->BytesLeftToRead(); } // Read data, all these methods may throw // The following two methods return ref to internal buffer that is overwritten // on each call to that method // These two methods are OBSOLETE, use ReadString and ReadWString instead! const wstring& Read_PW_STRING() const { return rep->Read_PW_STRING(); } const string& Read_PA_STRING() const { return rep->Read_PA_STRING(); } void ReadWString(std::wstring& theBufR) const { rep->ReadWString(theBufR); } void ReadString(std::string& theBufR) const { rep->ReadString(theBufR); } unsigned long ReadLong() const { return rep->ReadLong(); } unsigned short ReadShort() const { return rep->ReadShort(); } unsigned char ReadByte() const { return rep->ReadByte(); } const void * ReadBytes(long theNumBytes) const { return rep->ReadBytes(theNumBytes); } const void * PeekBytes(long theNumBytes) const { return rep->PeekBytes(theNumBytes); } // Compute size required to pack strings and wstrings static unsigned long ComputeStringPackSize (const std::string& theStrR) { return (sizeof(unsigned short) + theStrR.size()); } static unsigned long ComputeWStringPackSize(const std::wstring& theStrR) { return (sizeof(unsigned short) + theStrR.size() * sizeof(wchar_t)); } private: TRawData *rep; // ref counted member // Duplciate rep if needed when write operations occur. void CopyOnWrite(); }; // ** Begin message header definitions ** // *NOTE* // No padding of structs for message headers. Padding screws up size and // pack/unpack alogirthms #pragma pack (push, 1) // Old-style header for TMessages (no header type) // **OBSOLETE** struct TitanHeader { unsigned long _ServiceType; unsigned long _MessageType; explicit TitanHeader(unsigned long theServType=0, unsigned long theMsgType=0) : _ServiceType(theServType), _MessageType(theMsgType) {} // Cast helper function static TitanHeader &Cast( void *thePtr ) { return *(static_cast( thePtr ) ); } static const TitanHeader &Cast( const void *thePtr ) { return *(static_cast( thePtr ) ); } }; // MiniMessage header struct MiniHeader { unsigned char _HeaderType; unsigned char _ServiceType; unsigned char _MessageType; explicit MiniHeader(unsigned char theServType=0, unsigned char theMsgType=0) : _HeaderType(HeaderService1Message1), _ServiceType(theServType), _MessageType(theMsgType) {} }; // SmallMessage header struct SmallHeader { unsigned char _HeaderType; unsigned short _ServiceType; unsigned short _MessageType; explicit SmallHeader(unsigned short theServType=0, unsigned short theMsgType=0) : _HeaderType(HeaderService2Message2), _ServiceType(theServType), _MessageType(theMsgType) {} }; // LargeMessage header struct LargeHeader { unsigned char _HeaderType; unsigned long _ServiceType; unsigned long _MessageType; explicit LargeHeader(unsigned long theServType=0, unsigned long theMsgType=0) : _HeaderType(HeaderService4Message4), _ServiceType(theServType), _MessageType(theMsgType) {} }; // Restore previous packing level #pragma pack (pop) // ** End message header definitions ** // BaseMessage // Base class for all Titan message formats. The Pack() and Unpack() methods will // build a correct message packet in memory. If the object cannot build a packet // correctly, an exception should be thrown. // --------------------------------------------------------------------------- class BaseMessage : public TRawMsg { public: BaseMessage(); BaseMessage(const BaseMessage& msg); explicit BaseMessage(MessageClass theMessageClass) : mMessageClass(theMessageClass) {}; BaseMessage(unsigned long theDataLen, const void *theData =NULL); virtual ~BaseMessage(); BaseMessage& operator=(const BaseMessage&); virtual TRawMsg* Duplicate() const =0; virtual void* Pack() =0; // May throw virtual void Unpack(); // May throw virtual void UnpackHeader() const; virtual void* AllocateHeaderBuffer() { return AllocateNewBuffer(GetHeaderLength()); } virtual void* AllocateBodyBuffer(unsigned long size); // May throw virtual const void* GetBodyPtr() const { return( static_cast(static_cast(GetDataPtr()) + GetHeaderLength()) ); } virtual void* GetBodyPtr() { return( static_cast(static_cast(GetDataPtr()) + GetHeaderLength()) ); } virtual unsigned long GetHeaderLength() const =0; virtual unsigned char GetHeaderType() const =0; virtual unsigned char GetClearHeaderType() const =0; virtual unsigned char GetEncryptedHeaderType() const =0; virtual unsigned long GetServiceType(void) const =0; virtual unsigned long GetMessageType(void) const =0; virtual void SetServiceType(unsigned long theServiceType) =0; virtual void SetMessageType(unsigned long theMessageType) =0; MessageClass GetMessageClass() const { return mMessageClass; } virtual void Dump(std::ostream& os) const {}; // Class Constants enum { MAXMSG_SIZE = 131068 }; // Maximum message size protected: MessageClass mMessageClass; }; class MiniMessage : public BaseMessage { public: MiniMessage(); MiniMessage(const MiniMessage& theRSMsg); MiniMessage(unsigned long theDataLen, const void *theData =NULL); virtual ~MiniMessage(); MiniMessage& operator=(const MiniMessage&); virtual TRawMsg* Duplicate() const; virtual void* Pack(); // May throw const MiniHeader& GetHeader() const { return *(static_cast(GetDataPtr())); } unsigned long GetHeaderLength() const { return sizeof(MiniHeader); } unsigned char GetHeaderType(void) const { return GetHeader()._HeaderType; } unsigned char GetClearHeaderType() const { return HeaderService1Message1; } unsigned char GetEncryptedHeaderType() const { return MiniEncryptedService; } unsigned long GetServiceType(void) const { return GetHeader()._ServiceType; } unsigned long GetMessageType(void) const { return GetHeader()._MessageType; } void SetServiceType(unsigned long theServiceType) { GetHeaderRef()._ServiceType = theServiceType; } void SetMessageType(unsigned long theMessageType) { GetHeaderRef()._MessageType = theMessageType; } virtual void Dump(std::ostream& os) const; private: void SetHeaderType(unsigned char theHeaderType) { GetHeaderRef()._HeaderType = theHeaderType; } // Non-const version of getheader for set methods // MUST RETURN A NON-CONST REF!!! MiniHeader& GetHeaderRef() { return *(static_cast(GetDataPtr())); } }; class SmallMessage : public BaseMessage { public: SmallMessage(); SmallMessage(const SmallMessage& theRSMsg); SmallMessage(unsigned long theDataLen, const void *theData =NULL); virtual ~SmallMessage(); SmallMessage& operator=(const SmallMessage&); virtual TRawMsg* Duplicate() const; virtual void* Pack(); // May throw const SmallHeader& GetHeader() const { return *(static_cast(GetDataPtr())); } unsigned long GetHeaderLength() const { return sizeof(SmallHeader); } unsigned char GetHeaderType(void) const { return GetHeader()._HeaderType; } unsigned char GetClearHeaderType() const { return HeaderService2Message2; } unsigned char GetEncryptedHeaderType() const { return SmallEncryptedService; } unsigned long GetServiceType(void) const { return GetHeader()._ServiceType; } unsigned long GetMessageType(void) const { return GetHeader()._MessageType; } void SetServiceType(unsigned long theServiceType) { GetHeaderRef()._ServiceType = theServiceType; } void SetMessageType(unsigned long theMessageType) { GetHeaderRef()._MessageType = theMessageType; } virtual void Dump(std::ostream& os) const; private: void SetHeaderType(unsigned char theHeaderType) { GetHeaderRef()._HeaderType = theHeaderType; } // Non-const version of getheader for set methods // MUST RETURN A NON-CONST REF!!! SmallHeader& GetHeaderRef() { return *(static_cast(GetDataPtr())); } }; class LargeMessage : public BaseMessage { public: LargeMessage(); LargeMessage(const LargeMessage& theRSMsg); LargeMessage(unsigned long theDataLen, const void *theData =NULL); virtual ~LargeMessage(); LargeMessage& operator=(const LargeMessage&); virtual TRawMsg* Duplicate() const; virtual void* Pack(); // May throw const LargeHeader& GetHeader() const { return *(static_cast(GetDataPtr())); } unsigned long GetHeaderLength() const { return sizeof(LargeHeader); } unsigned char GetHeaderType(void) const { return GetHeader()._HeaderType; } unsigned char GetClearHeaderType() const { return HeaderService4Message4; } unsigned char GetEncryptedHeaderType() const { return LargeEncryptedService; } unsigned long GetServiceType(void) const { return GetHeader()._ServiceType; } unsigned long GetMessageType(void) const { return GetHeader()._MessageType; } void SetServiceType(unsigned long theServiceType) { GetHeaderRef()._ServiceType = theServiceType; } void SetMessageType(unsigned long theMessageType) { GetHeaderRef()._MessageType = theMessageType; } virtual void Dump(std::ostream& os) const; private: void SetHeaderType(unsigned char theHeaderType) { GetHeaderRef()._HeaderType = theHeaderType; } // Non-const version of getheader for set methods // MUST RETURN A NON-CONST REF!!! LargeHeader& GetHeaderRef() { return *(static_cast(GetDataPtr())); } }; // **OBSOLETE** // TMessage - old style titan messages without header type field // --------------------------------------------------------------------------- class TMessage : public BaseMessage { public: TMessage(); TMessage(const TMessage& Tmsg); explicit TMessage(unsigned long theDataLen, const void *theData=NULL); virtual ~TMessage(); TMessage& operator= (const TMessage&); virtual TRawMsg * Duplicate() const; virtual void * Pack(); // May throw // inlined const TitanHeader& GetHeader() const { return *(static_cast(GetDataPtr())); } unsigned long GetHeaderLength() const { return sizeof(TitanHeader); } unsigned char GetHeaderType(void) const { return (unsigned char)GetServiceType(); } unsigned char GetClearHeaderType() const { return GetHeaderType(); } unsigned char GetEncryptedHeaderType() const { return EncryptedService; } unsigned long GetServiceType(void) const { return GetHeader()._ServiceType; } unsigned long GetMessageType(void) const { return GetHeader()._MessageType; } void SetServiceType(unsigned long theServiceType ) { GetHeaderRef()._ServiceType = theServiceType; } void SetMessageType(unsigned long theMessageType ) { GetHeaderRef()._MessageType = theMessageType; } virtual void Dump(std::ostream& os) const; private: // Non-const version of getheader for set methods // MUST RETURN A NON-CONST REF!!! TitanHeader& GetHeaderRef() { return *(static_cast(GetDataPtr())); } }; // **END OBSOLETE** }; // namespace WONMsg inline std::ostream& operator<<(std::ostream& os, const WONMsg::BaseMessage& theMsgR) { theMsgR.Dump(os); return os; } #endif // H_TMessage