Message.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (c) 2001-2014
3 **
4 ** This file is part of the QuickFIX FIX Engine
5 **
6 ** This file may be distributed under the terms of the quickfixengine.org
7 ** license as defined by quickfixengine.org and appearing in the file
8 ** LICENSE included in the packaging of this file.
9 **
10 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 **
13 ** See http://www.quickfixengine.org/LICENSE for licensing information.
14 **
15 ** Contact ask@quickfixengine.org if any conditions of this licensing are
16 ** not clear to you.
17 **
18 ****************************************************************************/
19 
20 #ifdef _MSC_VER
21 #include "stdafx.h"
22 #else
23 #include "config.h"
24 #endif
25 
26 #include "Message.h"
27 #include "Utility.h"
28 #include "Values.h"
29 #include <iomanip>
30 
31 namespace FIX
32 {
33 std::auto_ptr<DataDictionary> Message::s_dataDictionary;
34 
36 : m_validStructure( true ) {}
37 
38 Message::Message( const std::string& string, bool validate )
39 throw( InvalidMessage )
40 : m_validStructure( true )
41 {
42  setString( string, validate );
43 }
44 
45 Message::Message( const std::string& string,
46  const DataDictionary& dataDictionary,
47  bool validate )
48 throw( InvalidMessage )
49 : m_validStructure( true )
50 {
51  setString( string, validate, &dataDictionary, &dataDictionary );
52 }
53 
54 Message::Message( const std::string& string,
55  const DataDictionary& sessionDataDictionary,
56  const DataDictionary& applicationDataDictionary,
57  bool validate )
58 throw( InvalidMessage )
59 : m_validStructure( true )
60 {
61  setStringHeader( string );
62  if( isAdmin() )
63  setString( string, validate, &sessionDataDictionary, &sessionDataDictionary );
64  else
65  setString( string, validate, &sessionDataDictionary, &applicationDataDictionary );
66 }
67 
68 bool Message::InitializeXML( const std::string& url )
69 {
70  try
71  {
72  std::auto_ptr<DataDictionary> p =
73  std::auto_ptr<DataDictionary>(new DataDictionary(url));
74  s_dataDictionary = p;
75  return true;
76  }
77  catch( ConfigError& )
78  { return false; }
79 }
80 
82 {
83  // required routing tags
84  BeginString beginString;
85  SenderCompID senderCompID;
86  TargetCompID targetCompID;
87 
88  m_header.removeField( beginString.getField() );
89  m_header.removeField( senderCompID.getField() );
90  m_header.removeField( targetCompID.getField() );
91 
92  if( header.getFieldIfSet( beginString ) )
93  {
94  if( beginString.getValue().size() )
95  m_header.setField( beginString );
96 
97  OnBehalfOfLocationID onBehalfOfLocationID;
98  DeliverToLocationID deliverToLocationID;
99 
100  m_header.removeField( onBehalfOfLocationID.getField() );
101  m_header.removeField( deliverToLocationID.getField() );
102 
103  if( beginString >= BeginString_FIX41 )
104  {
105  if( header.getFieldIfSet( onBehalfOfLocationID ) )
106  {
107  if( onBehalfOfLocationID.getValue().size() )
108  m_header.setField( DeliverToLocationID( onBehalfOfLocationID ) );
109  }
110 
111  if( header.getFieldIfSet( deliverToLocationID ) )
112  {
113  if( deliverToLocationID.getValue().size() )
114  m_header.setField( OnBehalfOfLocationID( deliverToLocationID ) );
115  }
116  }
117  }
118 
119  if( header.getFieldIfSet( senderCompID ) )
120  {
121  if( senderCompID.getValue().size() )
122  m_header.setField( TargetCompID( senderCompID ) );
123  }
124 
125  if( header.getFieldIfSet( targetCompID ) )
126  {
127  if( targetCompID.getValue().size() )
128  m_header.setField( SenderCompID( targetCompID ) );
129  }
130 
131  // optional routing tags
132  OnBehalfOfCompID onBehalfOfCompID;
133  OnBehalfOfSubID onBehalfOfSubID;
134  DeliverToCompID deliverToCompID;
135  DeliverToSubID deliverToSubID;
136 
137  m_header.removeField( onBehalfOfCompID.getField() );
138  m_header.removeField( onBehalfOfSubID.getField() );
139  m_header.removeField( deliverToCompID.getField() );
140  m_header.removeField( deliverToSubID.getField() );
141 
142  if( header.getFieldIfSet( onBehalfOfCompID ) )
143  {
144  if( onBehalfOfCompID.getValue().size() )
145  m_header.setField( DeliverToCompID( onBehalfOfCompID ) );
146  }
147 
148  if( header.getFieldIfSet( onBehalfOfSubID ) )
149  {
150  if( onBehalfOfSubID.getValue().size() )
151  m_header.setField( DeliverToSubID( onBehalfOfSubID ) );
152  }
153 
154  if( header.getFieldIfSet( deliverToCompID ) )
155  {
156  if( deliverToCompID.getValue().size() )
157  m_header.setField( OnBehalfOfCompID( deliverToCompID ) );
158  }
159 
160  if( header.getFieldIfSet( deliverToSubID ) )
161  {
162  if( deliverToSubID.getValue().size() )
163  m_header.setField( OnBehalfOfSubID( deliverToSubID ) );
164  }
165 }
166 
167 std::string Message::toString( int beginStringField,
168  int bodyLengthField,
169  int checkSumField ) const
170 {
171  std::string str;
172  return toString( str, beginStringField, bodyLengthField, checkSumField );
173 }
174 
175 std::string& Message::toString( std::string& str,
176  int beginStringField,
177  int bodyLengthField,
178  int checkSumField ) const
179 {
180  int length = bodyLength( beginStringField, bodyLengthField, checkSumField );
181  m_header.setField( IntField(bodyLengthField, length) );
182  m_trailer.setField( CheckSumField(checkSumField, checkSum(checkSumField)) );
183 
184 #if defined(_MSC_VER) && _MSC_VER < 1300
185  str = "";
186 #else
187  str.clear();
188 #endif
189 
190  /*small speculation about the space needed for FIX string*/
191  str.reserve( length + 64 );
192 
193  m_header.calculateString( str );
195  m_trailer.calculateString( str );
196 
197  return str;
198 }
199 
200 std::string Message::toXML() const
201 {
202  std::string str;
203  return toXML( str );
204 }
205 
206 std::string& Message::toXML( std::string& str ) const
207 {
208  std::stringstream stream;
209  stream << "<message>" << std::endl
210  << std::setw(2) << " " << "<header>" << std::endl
211  << toXMLFields(getHeader(), 4)
212  << std::setw(2) << " " << "</header>" << std::endl
213  << std::setw(2) << " " << "<body>" << std::endl
214  << toXMLFields(*this, 4)
215  << std::setw(2) << " " << "</body>" << std::endl
216  << std::setw(2) << " " << "<trailer>" << std::endl
217  << toXMLFields(getTrailer(), 4)
218  << std::setw(2) << " " << "</trailer>" << std::endl
219  << "</message>";
220 
221  return str = stream.str();
222 }
223 
224 std::string Message::toXMLFields(const FieldMap& fields, int space) const
225 {
226  std::stringstream stream;
228  std::string name;
229  for(i = fields.begin(); i != fields.end(); ++i)
230  {
231  int field = i->first;
232  std::string value = i->second.getString();
233 
234  stream << std::setw(space) << " " << "<field ";
235  if(s_dataDictionary.get() && s_dataDictionary->getFieldName(field, name))
236  {
237  stream << "name=\"" << name << "\" ";
238  }
239  stream << "number=\"" << field << "\"";
240  if(s_dataDictionary.get()
241  && s_dataDictionary->getValueName(field, value, name))
242  {
243  stream << " enum=\"" << name << "\"";
244  }
245  stream << ">";
246  stream << "<![CDATA[" << value << "]]>";
247  stream << "</field>" << std::endl;
248  }
249 
251  for(j = fields.g_begin(); j != fields.g_end(); ++j)
252  {
253  std::vector<FieldMap*>::const_iterator k;
254  for(k = j->second.begin(); k != j->second.end(); ++k)
255  {
256  stream << std::setw(space) << " " << "<group>" << std::endl
257  << toXMLFields(*(*k), space+2)
258  << std::setw(space) << " " << "</group>" << std::endl;
259  }
260  }
261 
262  return stream.str();
263 }
264 
265 void Message::setString( const std::string& string,
266  bool doValidation,
267  const DataDictionary* pSessionDataDictionary,
268  const DataDictionary* pApplicationDataDictionary )
269 throw( InvalidMessage )
270 {
271  clear();
272 
273  std::string::size_type pos = 0;
274  int count = 0;
275  std::string msg;
276 
277  static int const headerOrder[] =
278  {
282  };
283 
284  field_type type = header;
285 
286  while ( pos < string.size() )
287  {
288  FieldBase field = extractField( string, pos, pSessionDataDictionary, pApplicationDataDictionary );
289  if ( count < 3 && headerOrder[ count++ ] != field.getField() )
290  if ( doValidation ) throw InvalidMessage("Header fields out of order");
291 
292  if ( isHeaderField( field, pSessionDataDictionary ) )
293  {
294  if ( type != header )
295  {
296  if(m_field == 0) m_field = field.getField();
297  m_validStructure = false;
298  }
299 
300  if ( field.getField() == FIELD::MsgType )
301  msg = field.getString();
302 
303  m_header.setField( field, false );
304 
305  if ( pSessionDataDictionary )
306  setGroup( "_header_", field, string, pos, getHeader(), *pSessionDataDictionary );
307  }
308  else if ( isTrailerField( field, pSessionDataDictionary ) )
309  {
310  type = trailer;
311  m_trailer.setField( field, false );
312 
313  if ( pSessionDataDictionary )
314  setGroup( "_trailer_", field, string, pos, getTrailer(), *pSessionDataDictionary );
315  }
316  else
317  {
318  if ( type == trailer )
319  {
320  if(m_field == 0) m_field = field.getField();
321  m_validStructure = false;
322  }
323 
324  type = body;
325  setField( field, false );
326 
327  if ( pApplicationDataDictionary )
328  setGroup( msg, field, string, pos, *this, *pApplicationDataDictionary );
329  }
330  }
331 
332  if ( doValidation )
333  validate();
334 }
335 
336 void Message::setGroup( const std::string& msg, const FieldBase& field,
337  const std::string& string,
338  std::string::size_type& pos, FieldMap& map,
339  const DataDictionary& dataDictionary )
340 {
341  int group = field.getField();
342  int delim;
343  const DataDictionary* pDD = 0;
344  if ( !dataDictionary.getGroup( msg, group, delim, pDD ) ) return ;
345  std::auto_ptr<Group> pGroup;
346 
347  while ( pos < string.size() )
348  {
349  std::string::size_type oldPos = pos;
350  FieldBase field = extractField( string, pos, &dataDictionary, &dataDictionary, pGroup.get() );
351 
352  // Start a new group because...
353  if (// found delimiter
354  (field.getField() == delim) ||
355  // no delimiter, but field belongs to group OR field already processed
356  (pDD->isField( field.getField() ) && (pGroup.get() == 0 || pGroup->isSetField( field.getField() )) ))
357  {
358  if ( pGroup.get() )
359  {
360  map.addGroupPtr( group, pGroup.release(), false );
361  }
362  pGroup.reset( new Group( field.getField(), delim, pDD->getOrderedFields() ) );
363  }
364  else if ( !pDD->isField( field.getField() ) )
365  {
366  if ( pGroup.get() )
367  {
368  map.addGroupPtr( group, pGroup.release(), false );
369  }
370  pos = oldPos;
371  return ;
372  }
373 
374  if ( !pGroup.get() ) return ;
375  pGroup->setField( field, false );
376  setGroup( msg, field, string, pos, *pGroup, *pDD );
377  }
378 }
379 
380 bool Message::setStringHeader( const std::string& string )
381 {
382  clear();
383 
384  std::string::size_type pos = 0;
385  int count = 0;
386 
387  while ( pos < string.size() )
388  {
389  FieldBase field = extractField( string, pos );
390  if ( count < 3 && headerOrder[ count++ ] != field.getField() )
391  return false;
392 
393  if ( isHeaderField( field ) )
394  m_header.setField( field, false );
395  else break;
396  }
397  return true;
398 }
399 
400 bool Message::isHeaderField( int field )
401 {
402  switch ( field )
403  {
404  case FIELD::BeginString:
405  case FIELD::BodyLength:
406  case FIELD::MsgType:
407  case FIELD::SenderCompID:
408  case FIELD::TargetCompID:
412  case FIELD::MsgSeqNum:
413  case FIELD::SenderSubID:
415  case FIELD::TargetSubID:
421  case FIELD::PossDupFlag:
422  case FIELD::PossResend:
423  case FIELD::SendingTime:
425  case FIELD::XmlDataLen:
426  case FIELD::XmlData:
430  case FIELD::ApplVerID:
432  case FIELD::NoHops:
433  return true;
434  default:
435  return false;
436  };
437 }
438 
440  const DataDictionary* pD )
441 {
442  if ( isHeaderField( field.getField() ) ) return true;
443  if ( pD ) return pD->isHeaderField( field.getField() );
444  return false;
445 }
446 
447 bool Message::isTrailerField( int field )
448 {
449  switch ( field )
450  {
452  case FIELD::Signature:
453  case FIELD::CheckSum:
454  return true;
455  default:
456  return false;
457  };
458 }
459 
461  const DataDictionary* pD )
462 {
463  if ( isTrailerField( field.getField() ) ) return true;
464  if ( pD ) return pD->isTrailerField( field.getField() );
465  return false;
466 }
467 
468 SessionID Message::getSessionID( const std::string& qualifier ) const
469 throw( FieldNotFound )
470 {
471  BeginString beginString;
472  SenderCompID senderCompID;
473  TargetCompID targetCompID;
474 
475  getHeader().getField( beginString );
476  getHeader().getField( senderCompID );
477  getHeader().getField( targetCompID );
478 
479  return SessionID( beginString, senderCompID, targetCompID, qualifier );
480 }
481 
482 void Message::setSessionID( const SessionID& sessionID )
483 {
484  getHeader().setField( sessionID.getBeginString() );
485  getHeader().setField( sessionID.getSenderCompID() );
486  getHeader().setField( sessionID.getTargetCompID() );
487 }
488 
490 {
491  try
492  {
493  const BodyLength& aBodyLength = FIELD_GET_REF( m_header, BodyLength );
494 
495  const int expectedLength = (int)aBodyLength;
496  const int actualLength = bodyLength();
497 
498  if ( expectedLength != actualLength )
499  {
500  std::stringstream text;
501  text << "Expected BodyLength=" << actualLength
502  << ", Received BodyLength=" << expectedLength;
503  throw InvalidMessage(text.str());
504  }
505 
506  const CheckSum& aCheckSum = FIELD_GET_REF( m_trailer, CheckSum );
507 
508  const int expectedChecksum = (int)aCheckSum;
509  const int actualChecksum = checkSum();
510 
511  if ( expectedChecksum != actualChecksum )
512  {
513  std::stringstream text;
514  text << "Expected CheckSum=" << actualChecksum
515  << ", Received CheckSum=" << expectedChecksum;
516  throw InvalidMessage(text.str());
517  }
518  }
519  catch ( FieldNotFound& e )
520  {
521  const std::string fieldName = ( e.field == FIX::FIELD::BodyLength ) ? "BodyLength" : "CheckSum";
522  throw InvalidMessage( fieldName + std::string(" is missing") );
523  }
524  catch ( IncorrectDataFormat& e )
525  {
526  const std::string fieldName = ( e.field == FIX::FIELD::BodyLength ) ? "BodyLength" : "CheckSum";
527  throw InvalidMessage( fieldName + std::string(" has wrong format: ") + e.detail );
528  }
529 }
530 
531 FIX::FieldBase Message::extractField( const std::string& string, std::string::size_type& pos,
532  const DataDictionary* pSessionDD /*= 0*/, const DataDictionary* pAppDD /*= 0*/,
533  const Group* pGroup /*= 0*/ )
534 {
535  std::string::const_iterator const tagStart = string.begin() + pos;
536  std::string::const_iterator const strEnd = string.end();
537 
538  std::string::const_iterator const equalSign = std::find( tagStart, strEnd, '=' );
539  if( equalSign == strEnd )
540  throw InvalidMessage("Equal sign not found in field");
541 
542  int field = 0;
543  IntConvertor::convert( tagStart, equalSign, field );
544 
545  std::string::const_iterator const valueStart = equalSign + 1;
546 
547  std::string::const_iterator soh = std::find( valueStart, strEnd, '\001' );
548  if ( soh == strEnd )
549  throw InvalidMessage("SOH not found at end of field");
550 
551  if ( IsDataField( field, pSessionDD, pAppDD ) )
552  {
553  // Assume length field is 1 less.
554  int lenField = field - 1;
555  // Special case for Signature which violates above assumption.
556  if ( field == FIELD::Signature ) lenField = FIELD::SignatureLength;
557 
558  if ( pGroup && pGroup->isSetField( lenField ) )
559  {
560  const std::string& fieldLength = pGroup->getField( lenField );
561  soh = valueStart + atol( fieldLength.c_str() );
562  }
563  else if ( isSetField( lenField ) )
564  {
565  const std::string& fieldLength = getField( lenField );
566  soh = valueStart + atol( fieldLength.c_str() );
567  }
568  }
569 
570  std::string::const_iterator const tagEnd = soh + 1;
571  pos = std::distance( string.begin(), tagEnd );
572 
573  return FieldBase (
574  field,
575  valueStart,
576  soh,
577  tagStart,
578  tagEnd );
579 }
580 }
const int ApplVerID
int checkSum(int checkSumField=FIELD::CheckSum) const
Definition: Message.h:213
bool isSetField(const FieldBase &field) const
Check to see if a field is set.
Definition: FieldMap.h:144
const int SecureDataLen
iterator begin() const
Definition: FieldMap.h:214
const int OrigSendingTime
Field has a badly formatted value.
Definition: Exceptions.h:146
const int DeliverToLocationID
Fields::const_iterator iterator
Definition: FieldMap.h:59
bool getFieldIfSet(FieldBase &field) const
Get a field if set.
Definition: FieldMap.h:102
static bool IsDataField(int field, const DataDictionary *pSessionDD, const DataDictionary *pAppDD)
Definition: Message.h:320
const std::string & getString() const
Get the string representation of the fields value.
Definition: Field.h:112
Represents a data dictionary for a version of FIX.
const int CstmApplVerID
static bool InitializeXML(const std::string &string)
Set global data dictionary for encoding messages into XML.
Definition: Message.cpp:68
const int OnBehalfOfCompID
Groups::const_iterator g_iterator
Definition: FieldMap.h:61
void reverseRoute(const Header &)
Add header informations depending on a source message.
Definition: Message.cpp:81
const int NoHops
const int OnBehalfOfLocationID
bool getGroup(const std::string &msg, int field, int &delim, const DataDictionary *&pDataDictionary) const
const int OnBehalfOfSubID
Field that contains a checksum value.
Definition: Field.h:473
bool setStringHeader(const std::string &string)
Set a messages header from a string This is an optimization that can be used to get useful informatio...
Definition: Message.cpp:380
iterator end() const
Definition: FieldMap.h:215
std::string toXMLFields(const FieldMap &fields, int space) const
Definition: Message.cpp:224
void validate()
Definition: Message.cpp:489
const int PossResend
const TargetCompID & getTargetCompID() const
Definition: SessionID.h:57
std::string detail
Definition: Exceptions.h:42
const int LastMsgSeqNumProcessed
bool isHeaderField(int field) const
void setGroup(const std::string &msg, const FieldBase &field, const std::string &string, std::string::size_type &pos, FieldMap &map, const DataDictionary &dataDictionary)
Definition: Message.cpp:336
static std::string convert(signed_int value)
const int TargetLocationID
const int SendingTime
Definition: Acceptor.cpp:34
const Header & getHeader() const
Getter for the message header.
Definition: Message.h:192
const int XmlData
FieldBase & getField(FieldBase &field) const
Get a field without type checking.
Definition: FieldMap.h:112
Base class for all FIX repeating groups.
Definition: Group.h:40
Stores and organizes a collection of Fields.
Definition: FieldMap.h:46
SessionID getSessionID(const std::string &qualifier="") const
Returns the session ID of the intended recipient.
Definition: Message.cpp:468
const int DeliverToSubID
int bodyLength(int beginStringField=FIELD::BeginString, int bodyLengthField=FIELD::BodyLength, int checkSumField=FIELD::CheckSum) const
Definition: Message.h:205
const int SenderSubID
Application is not configured correctly
Definition: Exceptions.h:87
FieldBase extractField(const std::string &string, std::string::size_type &pos, const DataDictionary *pSessionDD=0, const DataDictionary *pAppDD=0, const Group *pGroup=0)
Definition: Message.cpp:531
std::string toString(int beginStringField=FIELD::BeginString, int bodyLengthField=FIELD::BodyLength, int checkSumField=FIELD::CheckSum) const
Get a string representation of the message.
Definition: Message.cpp:167
const int TargetCompID
const Trailer & getTrailer() const
Getter for the message trailer.
Definition: Message.h:196
void setSessionID(const SessionID &sessionID)
Sets the session ID of the intended recipient.
Definition: Message.cpp:482
const int SenderLocationID
message_order const & getOrderedFields() const
Field not found inside a message.
Definition: Exceptions.h:57
const int MessageEncoding
void setField(const FieldBase &field, bool overwrite=true)
Set a field without type checking.
Definition: FieldMap.h:79
bool isTrailerField(int field) const
std::string & calculateString(std::string &) const
Definition: FieldMap.cpp:176
int getField() const
Get the fields integer tag.
Definition: Field.h:108
const BeginString & getBeginString() const
Definition: SessionID.h:53
void removeField(int field)
Remove a field. If field is not present, this is a no-op.
Definition: FieldMap.cpp:117
const char BeginString_FIX41[]
Definition: Values.h:35
Field that contains an integer value.
Definition: Field.h:352
const int SenderCompID
const int SignatureLength
g_iterator g_end() const
Definition: FieldMap.h:217
int m_field
Definition: Message.h:341
const int XmlDataLen
g_iterator g_begin() const
Definition: FieldMap.h:216
static std::auto_ptr< DataDictionary > s_dataDictionary
Definition: Message.h:342
Base representation of all Field classes.
Definition: Field.h:45
void addGroupPtr(int field, FieldMap *group, bool setCount=true)
Acquire ownership of Group object.
Definition: FieldMap.cpp:65
bool isField(int field) const
void clear()
Definition: Message.h:242
const int DeliverToCompID
const int PossDupFlag
const int TargetSubID
const int OnBehalfOfSendingTime
Header m_header
Definition: Message.h:338
const int BeginString
const int MsgSeqNum
const int Signature
Unique session id consists of BeginString, SenderCompID and TargetCompID.
Definition: SessionID.h:30
std::string toXML() const
Get a XML representation of the message.
Definition: Message.cpp:200
friend class DataDictionary
Definition: Message.h:69
Not a recognizable message.
Definition: Exceptions.h:80
const SenderCompID & getSenderCompID() const
Definition: SessionID.h:55
const int BodyLength
void setString(const std::string &string)
Set a message based on a string representation This will fill in the fields on the message by parsing...
Definition: Message.h:162
#define FIELD_GET_REF(MAP, FLD)
Definition: FieldMap.h:238
const int MsgType
static bool isHeaderField(int field)
Definition: Message.cpp:400
static bool isTrailerField(int field)
Definition: Message.cpp:447
bool m_validStructure
Definition: Message.h:340
const int CheckSum
static int const headerOrder[]
Definition: Message.h:40
Trailer m_trailer
Definition: Message.h:339
bool isAdmin() const
Definition: Message.h:219

Generated on Thu Sep 5 2019 11:07:58 for QuickFIX by doxygen 1.8.13 written by Dimitri van Heesch, © 1997-2001