Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / net / message.cpp
blob5110bed45f38ff8ae51b68f8fb377fd8315a4cb0
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdnet.h"
19 #include "nel/net/message.h"
21 /*#ifdef MESSAGES_PLAIN_TEXT
22 #pragma message( "CMessage: compiling messages as plain text" )
23 #else
24 #pragma message( "CMessage: compiling messages as binary" )
25 #endif*/
27 namespace NLNET
30 bool CMessage::_DefaultStringMode = false;
32 const char *LockedSubMessageError = "a sub message is forbidden";
34 #define FormatLong 1
35 #define FormatShort 0
39 * Constructor by name
41 CMessage::CMessage (const std::string &name, bool inputStream, TStreamFormat streamformat, uint32 defaultCapacity) :
42 NLMISC::CMemStream (inputStream, false, defaultCapacity),
43 _Type(OneWay), _SubMessagePosR(0), _LengthR(0), _HeaderSize(0xFFFFFFFF), _TypeSet (false)
45 init( name, streamformat );
50 * Utility method
52 void CMessage::init( const std::string &name, TStreamFormat streamformat )
54 if ( streamformat == UseDefault )
56 setStringMode( _DefaultStringMode );
58 else
60 setStringMode( streamformat == String );
63 if (!name.empty())
64 setType (name);
69 * Constructor with copy from CMemStream
71 CMessage::CMessage (NLMISC::CMemStream &memstr) :
72 NLMISC::CMemStream( memstr ),
73 _Type(OneWay), _SubMessagePosR(0), _LengthR(0), _HeaderSize(0xFFFFFFFF), _TypeSet (false)
75 sint32 pos = getPos();
76 bool reading = isReading();
77 if ( reading ) // force input mode to read the type
78 readType(); // sets _TypeSet, _HeaderSize and _LengthR
79 else
80 invert(); // calls readType()
81 if ( ! reading )
82 invert(); // set output mode back if necessary
83 seek( pos, begin ); // sets the same position as the one in the memstream
88 * Copy constructor
90 CMessage::CMessage (const CMessage &other)
91 : CMemStream(),
92 _TypeSet(false)
94 operator= (other);
98 * Assignment operator
100 CMessage &CMessage::operator= (const CMessage &other)
102 // nlassertex( (!other.isReading()) || (!other.hasLockedSubMessage()), ("Storing %s", LockedSubMessageError) );
103 nlassertex( (!isReading()) || (!hasLockedSubMessage()), ("Assigning %s", LockedSubMessageError) );
104 if ( other.hasLockedSubMessage() )
106 assignFromSubMessage(other);
108 else
111 CMemStream::operator= (other);
112 _Type = other._Type;
113 _TypeSet = other._TypeSet;
114 _Name = other._Name;
115 _HeaderSize = other._HeaderSize;
116 _SubMessagePosR = other._SubMessagePosR;
117 _LengthR = other._LengthR;
120 return *this;
123 void CMessage::swap(CMessage &other)
125 nlassert( !hasLockedSubMessage() );
126 CMemStream::swap(other);
127 _Name.swap(other._Name);
128 std::swap(_SubMessagePosR, other._SubMessagePosR);
129 std::swap(_LengthR, other._LengthR);
130 std::swap(_HeaderSize, other._HeaderSize);
131 std::swap(_TypeSet, other._TypeSet);
132 std::swap(_Type, other._Type);
137 * Similar to operator=, but makes the current message contain *only* the locked sub message in msgin
138 * or the whole msgin if it is not locked
140 * Preconditions:
141 * - msgin is an input message (isReading())
142 * - The current message is blank (new or reset with clear())
144 * Postconditions:
145 * - If msgin has been locked using lockSubMessage(), the current message contains only the locked
146 * sub message in msgin, otherwise the current message is exactly msgin
147 * - The current message is an input message, it is not locked
149 void CMessage::assignFromSubMessage( const CMessage& msgin )
151 nlassert( msgin.isReading() );
152 nlassert( ! _TypeSet );
153 if ( ! isReading() )
154 invert();
156 if ( msgin.hasLockedSubMessage() )
158 fill( msgin.buffer(), msgin._LengthR );
159 readType();
160 seek( msgin.getPos(), IStream::begin );
162 else
164 operator=( msgin );
170 * Sets the message type as a string and put it in the buffer if we are in writing mode
172 void CMessage::setType (const std::string &name, TMessageType type)
174 // check if we already do a setType ()
175 nlassert (!_TypeSet);
176 // don't accept empty string
177 nlassert (!name.empty ());
179 _Name = name;
180 _Type = type;
182 if (!isReading ())
184 // check if they don't already serial some stuffs
185 nlassert (length () == 0);
187 // if we can send the id instead of the string, "just do it" (c)nike!
188 //NLMISC::CStringIdArray::TStringId id = _SIDA->getId (name);
190 // Force binary mode for header
191 bool msgmode = _StringMode;
192 _StringMode = false;
194 // debug features, we number all packet to be sure that they are all sent and received
195 // \todo remove this debug feature when ok
196 // this value will be fill after in the callback function
197 uint32 zeroValue = 123;
198 serial (zeroValue);
201 TFormat format;
202 format.LongFormat = FormatLong;
203 format.StringMode = msgmode;
204 format.MessageType = _Type;
205 //nldebug( "OUT format = %hu", (uint16)format );
206 serial (format);
208 // End of binary header
209 _StringMode = msgmode;
211 serial ((std::string&)name);
213 _HeaderSize = getPos ();
216 _TypeSet = true;
221 * Warning: MUST be of the same size than previous name!
222 * Output message only.
224 void CMessage::changeType (const std::string &name)
226 sint32 prevPos = getPos();
227 seek( sizeof(uint32)+sizeof(uint8), begin );
228 serial ((std::string&)name);
229 seek( prevPos, begin );
234 * Returns the size, in byte of the header that contains the type name of the message or the type number
236 uint32 CMessage::getHeaderSize () const
238 nlassert (_HeaderSize != 0xFFFFFFFF);
239 nlassert(!hasLockedSubMessage());
240 return _HeaderSize;
245 * The message was filled with an CMemStream, Now, we'll get the message type on this buffer
247 void CMessage::readType ()
249 nlassert (isReading ());
251 // debug features, we number all packet to be sure that they are all sent and received
252 // \todo remove this debug feature when ok
254 // we remove the message from the message
255 resetSubMessageInternals();
256 const uint HeaderSize = 4;
257 seek (HeaderSize, begin);
258 // uint32 zeroValue;
259 // serial (zeroValue);
261 // Force binary mode for header
262 _StringMode = false;
264 TFormat format;
265 serial (format);
266 //nldebug( "IN format = %hu", (uint16)format );
268 // Set mode for the following of the buffer
269 _StringMode = format.StringMode;
271 std::string name;
272 serial (name);
273 setType (name, TMessageType(format.MessageType));
274 _HeaderSize = getPos();
279 * Get the message name (input message only) and advance the current pos
281 std::string CMessage::readTypeAtCurrentPos() const
283 nlassert( isReading() );
285 const uint HeaderSize = 4;
286 seek( HeaderSize, current );
288 bool sm = _StringMode;
289 _StringMode = false;
291 TFormat format;
292 nlRead(*this, serial, format );
293 bool LongFormat = format.LongFormat;
294 _StringMode = format.StringMode;
295 _Type = TMessageType(format.MessageType);
297 if ( LongFormat )
299 std::string name;
300 nlRead(*this, serial, name );
301 _StringMode = sm;
302 return name;
304 else
305 nlerror( "Id not supported" );
308 _StringMode = sm;
309 return "";
313 // Returns true if the message type was already set
314 bool CMessage::typeIsSet () const
316 return _TypeSet;
319 // Clear the message. With this function, you can reuse a message to create another message
320 void CMessage::clear ()
322 nlassertex( (!isReading()) || (!hasLockedSubMessage()), ("Clearing %s", LockedSubMessageError) );
324 CMemStream::clear ();
325 _TypeSet = false;
326 _SubMessagePosR = 0;
327 _LengthR = 0;
331 * Returns the type name in string if available. Be sure that the message have the name of the message type
333 std::string CMessage::getName () const
335 if ( hasLockedSubMessage() )
337 CMessage& notconstMsg = const_cast<CMessage&>(*this);
338 sint32 savedPos = notconstMsg.getPos();
339 uint32 subPosSaved = _SubMessagePosR;
340 uint32 lenthRSaved = _LengthR;
341 const_cast<uint32&>(_SubMessagePosR) = 0;
342 // const_cast<uint32&>(_LengthR) = _Buffer.size();
343 const_cast<uint32&>(_LengthR) = _Buffer.getBuffer().size();
344 notconstMsg.seek( subPosSaved, begin ); // not really const... but removing the const from getName() would need too many const changes elsewhere
345 std::string name = notconstMsg.readTypeAtCurrentPos();
346 notconstMsg.seek( subPosSaved+savedPos, begin );
347 const_cast<uint32&>(_SubMessagePosR) = subPosSaved;
348 const_cast<uint32&>(_LengthR) = lenthRSaved;
349 return name;
351 else
353 nlassert (_TypeSet);
354 return _Name;
358 CMessage::TMessageType CMessage::getType() const
360 if ( hasLockedSubMessage() )
362 CMessage& notconstMsg = const_cast<CMessage&>(*this);
363 sint32 savedPos = notconstMsg.getPos();
364 uint32 subPosSaved = _SubMessagePosR;
365 uint32 lenthRSaved = _LengthR;
366 const_cast<uint32&>(_SubMessagePosR) = 0;
367 // const_cast<uint32&>(_LengthR) = _Buffer.size();
368 const_cast<uint32&>(_LengthR) = _Buffer.getBuffer().size();
369 notconstMsg.seek( subPosSaved, begin ); // not really const... but removing the const from getName() would need too many const changes elsewhere
370 notconstMsg.readTypeAtCurrentPos();
371 notconstMsg.seek( subPosSaved+savedPos, begin );
372 const_cast<uint32&>(_SubMessagePosR) = subPosSaved;
373 const_cast<uint32&>(_LengthR) = lenthRSaved;
374 return _Type;
376 else
378 nlassert (_TypeSet);
379 return _Type;
384 /* Returns a readable string to display it to the screen. It's only for debugging purpose!
385 * Don't use it for anything else than to debugging, the string format could change in the future.
386 * \param hexFormat If true, display all bytes in hexadecimal
387 * \param textFormat If true, display all bytes as chars (above 31, otherwise '.')
389 std::string CMessage::toString( bool hexFormat, bool textFormat ) const
391 //nlassert (_TypeSet);
392 std::string s = "('" + _Name + "')";
393 if ( hexFormat )
394 s += " " + CMemStream::toString( true );
395 if ( textFormat )
396 s += " " + CMemStream::toString( false );
397 return s;
402 * Return an input stream containing the stream beginning in the message at the specified pos
404 NLMISC::CMemStream CMessage::extractStreamFromPos( sint32 pos )
406 NLMISC::CMemStream msg( true );
407 sint32 len = length() - pos;
408 memcpy( msg.bufferToFill( len ), buffer() + pos, len );
409 return msg;
414 * Encapsulate/decapsulate another message inside the current message
416 void CMessage::serialMessage( CMessage& msg )
418 if ( isReading() )
420 // Init 'msg' with the contents serialised from 'this'
421 uint32 len;
422 serial( len );
423 if ( ! msg.isReading() )
424 msg.invert();
425 serialBuffer( msg.bufferToFill( len ), len );
426 msg.readType();
427 msg.invert();
428 msg.seek( 0, CMemStream::end );
430 else
432 // Store into 'this' the contents of 'msg'
433 uint32 len = msg.length();
434 serial( len );
435 serialBuffer( const_cast<uint8*>(msg.buffer()), msg.length() );