1 /*
2  *  Message.h
3  *  Created by Woody Zenfell, III on Sun Aug 31 2003.
4  */
5 
6 /*
7   Copyright (c) 2003, Woody Zenfell, III
8 
9   Permission is hereby granted, free of charge, to any person obtaining a copy
10   of this software and associated documentation files (the "Software"), to deal
11   in the Software without restriction, including without limitation the rights
12   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13   copies of the Software, and to permit persons to whom the Software is
14   furnished to do so, subject to the following conditions:
15 
16   The above copyright notice and this permission notice shall be included in
17   all copies or substantial portions of the Software.
18 
19   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25   SOFTWARE.
26 */
27 
28 #ifndef MESSAGE_H
29 #define MESSAGE_H
30 
31 #include <string.h>	// memcpy
32 #include "SDL.h"
33 
34 typedef Uint16 MessageTypeID;
35 
36 class UninflatedMessage;
37 
38 class Message
39 {
40 public:
41 	virtual	MessageTypeID		type() const = 0;
42 
43 	// May return false or raise an exception on failed inflation
44 	virtual	bool			inflateFrom(const UninflatedMessage& inUninflated) = 0;
45 
46 	// Caller must dispose of returned message via 'delete'
47 	virtual	UninflatedMessage*	deflate() const = 0;
48 
49 	virtual Message*		clone() const = 0;
50 
~Message()51 	virtual ~Message() {}
52 
53 protected:
54 };
55 
56 
57 
58 class UninflatedMessage : public Message
59 {
60 public:
61 	enum { kTypeID = 0xffff };
62 
63 	// If bytes are provided, this object takes ownership of them (does not copy).
64 	// If no bytes are provided, this object creates a buffer of size inLength.
65 	//    Clients should write into the pointer returned by buffer().
66 	UninflatedMessage(MessageTypeID inType, size_t inLength, Uint8* inBytes = NULL)
mType(inType)67 		: mType(inType), mLength(inLength), mBuffer(inBytes)
68 	{
69 		if(mBuffer == NULL)
70 			mBuffer = new Uint8[mLength];
71 	}
72 
UninflatedMessage(const UninflatedMessage & inSource)73 	UninflatedMessage(const UninflatedMessage& inSource) { copyToThis(inSource); }
74 
75 	UninflatedMessage& operator =(const UninflatedMessage& inSource)
76 	{
77 		if(&inSource != this)
78 			copyToThis(inSource);
79 
80 		return *this;
81 	}
82 
type()83 	MessageTypeID		type() const	{ return kTypeID; }
inflateFrom(const UninflatedMessage & inUninflated)84 	bool			inflateFrom(const UninflatedMessage& inUninflated) { *this = inUninflated; return true; }
deflate()85 	UninflatedMessage*	deflate() const { return new UninflatedMessage(*this); }
86 
clone()87 	UninflatedMessage* clone() const { return new UninflatedMessage(*this); }
88 
~UninflatedMessage()89 	~UninflatedMessage()	{ delete [] mBuffer; }
90 
inflatedType()91 	MessageTypeID	inflatedType() const	{ return mType; }
length()92 	size_t		length() const		{ return mLength; }
buffer()93 	Uint8*		buffer()		{ return mBuffer; }
buffer()94 	const Uint8*	buffer() const		{ return mBuffer; }
95 
96 private:
copyToThis(const UninflatedMessage & inSource)97 	void copyToThis(const UninflatedMessage& inSource)
98 	{
99 		mType	= inSource.mType;
100 		mLength	= inSource.mLength;
101 		mBuffer	= new Uint8[mLength];
102 		memcpy(mBuffer, inSource.mBuffer, mLength);
103 	}
104 
105 	MessageTypeID	mType;
106 	size_t		mLength;
107 	Uint8*		mBuffer;
108 };
109 
110 
111 
112 class AIStream;
113 class AOStream;
114 
115 class SmallMessageHelper : public Message
116 {
117 public:
118 	bool			inflateFrom(const UninflatedMessage& inUninflated);
119 	UninflatedMessage*	deflate() const;
120 
121 protected:
122 	virtual bool	reallyInflateFrom(AIStream& inStream) = 0;
123 	virtual void	reallyDeflateTo(AOStream& inStream) const = 0;
124 
125 private:
126 };
127 
128 
129 
130 class BigChunkOfDataMessage : public Message
131 {
132 public:
133 	BigChunkOfDataMessage(MessageTypeID inType, const Uint8* inBuffer = NULL, size_t inLength = 0);
BigChunkOfDataMessage(const BigChunkOfDataMessage & other)134 	BigChunkOfDataMessage(const BigChunkOfDataMessage& other) : mLength(0), mBuffer(NULL)
135 	{
136 		mType = other.type();
137 		copyBufferFrom(other.buffer(), other.length());
138 	}
139 
140 	BigChunkOfDataMessage& operator =(const BigChunkOfDataMessage& other)
141 	{
142 		if(&other != this)
143 		{
144 			mType = other.type();
145 			copyBufferFrom(other.buffer(), other.length());
146 		}
147 
148 		return *this;
149 	}
150 
151 	bool			inflateFrom(const UninflatedMessage& inUninflated);
152 	UninflatedMessage*	deflate() const;
type()153 	MessageTypeID		type() const	{ return mType; }
154 
155 	void			copyBufferFrom(const Uint8* inBuffer, size_t inLength);
156 
length()157 	size_t			length() const	{ return mLength; }
buffer()158 	Uint8*			buffer()	{ return mBuffer; }
buffer()159 	const Uint8*		buffer() const	{ return mBuffer; }
160 
161 	BigChunkOfDataMessage*	clone() const;
162 
163 	~BigChunkOfDataMessage();
164 
165 private:
166 	MessageTypeID	mType;
167 	size_t		mLength;
168 	Uint8*		mBuffer;
169 };
170 
171 
172 
173 template <typename tValueType>
174 class SimpleMessage : public SmallMessageHelper
175 {
176 public:
177 	typedef tValueType ValueType;
178 
SimpleMessage(MessageTypeID inType)179 	SimpleMessage(MessageTypeID inType)
180 		: mType(inType)
181 	{
182 		// Use default initializer for value
183 		new (static_cast<void*>(&mValue)) tValueType();
184 	}
185 
SimpleMessage(MessageTypeID inType,const tValueType & inValue)186 	SimpleMessage(MessageTypeID inType, const tValueType& inValue)
187 		: mType(inType), mValue(inValue)
188 	{
189 	}
190 
clone()191 	SimpleMessage<tValueType>* clone() const
192 		{ return new SimpleMessage<tValueType>(*this); }
193 
type()194 	MessageTypeID type() const { return mType; }
195 
setValue(const tValueType & inValue)196 	void setValue(const tValueType& inValue) { mValue = inValue; }
value()197 	const tValueType& value() const { return mValue; }
198 
199 protected:
reallyDeflateTo(AOStream & inStream)200 	void	reallyDeflateTo(AOStream& inStream) const
201 	{
202 		inStream << mValue;
203 	}
204 
reallyInflateFrom(AIStream & inStream)205 	bool	reallyInflateFrom(AIStream& inStream)
206 	{
207 		inStream >> mValue;
208 		return true;
209 	}
210 
211 private:
212 	MessageTypeID	mType;
213 	tValueType	mValue;
214 };
215 
216 
217 
218 template <MessageTypeID tMessageType>
219 class DatalessMessage : public Message
220 {
221 public:
222 	enum { kType = tMessageType };
223 
type()224 	MessageTypeID type() const { return kType; }
225 
inflateFrom(const UninflatedMessage & inUninflated)226 	bool inflateFrom(const UninflatedMessage& inUninflated)
227 	{
228 		return inUninflated.inflatedType() == kType && inUninflated.length() == 0;
229 	}
230 
deflate()231 	UninflatedMessage* deflate() const { return new UninflatedMessage(kType, 0); }
232 
clone()233 	DatalessMessage<tMessageType>* clone() const
234 	{ return new DatalessMessage<tMessageType>; }
235 };
236 
237 #endif // MESSAGE_H
238