quickfix_ruby 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/quickfix/Acceptor.cpp +248 -0
- data/ext/quickfix/Acceptor.h +127 -0
- data/ext/quickfix/Allocator.h +9 -0
- data/ext/quickfix/Application.h +127 -0
- data/ext/quickfix/AtomicCount.h +109 -0
- data/ext/quickfix/DOMDocument.h +74 -0
- data/ext/quickfix/DataDictionary.cpp +618 -0
- data/ext/quickfix/DataDictionary.h +539 -0
- data/ext/quickfix/DataDictionaryProvider.cpp +71 -0
- data/ext/quickfix/DataDictionaryProvider.h +70 -0
- data/ext/quickfix/DatabaseConnectionID.h +105 -0
- data/ext/quickfix/DatabaseConnectionPool.h +91 -0
- data/ext/quickfix/Dictionary.cpp +162 -0
- data/ext/quickfix/Dictionary.h +94 -0
- data/ext/quickfix/Event.h +95 -0
- data/ext/quickfix/Exceptions.h +299 -0
- data/ext/quickfix/Field.h +672 -0
- data/ext/quickfix/FieldConvertors.h +863 -0
- data/ext/quickfix/FieldMap.cpp +238 -0
- data/ext/quickfix/FieldMap.h +244 -0
- data/ext/quickfix/FieldNumbers.h +46 -0
- data/ext/quickfix/FieldTypes.cpp +64 -0
- data/ext/quickfix/FieldTypes.h +698 -0
- data/ext/quickfix/Fields.h +31 -0
- data/ext/quickfix/FileLog.cpp +200 -0
- data/ext/quickfix/FileLog.h +112 -0
- data/ext/quickfix/FileStore.cpp +332 -0
- data/ext/quickfix/FileStore.h +129 -0
- data/ext/quickfix/FixFieldNumbers.h +1537 -0
- data/ext/quickfix/FixFields.h +1538 -0
- data/ext/quickfix/FixValues.h +3281 -0
- data/ext/quickfix/FlexLexer.h +188 -0
- data/ext/quickfix/Group.cpp +64 -0
- data/ext/quickfix/Group.h +73 -0
- data/ext/quickfix/HtmlBuilder.h +186 -0
- data/ext/quickfix/HttpConnection.cpp +739 -0
- data/ext/quickfix/HttpConnection.h +78 -0
- data/ext/quickfix/HttpMessage.cpp +149 -0
- data/ext/quickfix/HttpMessage.h +133 -0
- data/ext/quickfix/HttpParser.cpp +49 -0
- data/ext/quickfix/HttpParser.h +54 -0
- data/ext/quickfix/HttpServer.cpp +169 -0
- data/ext/quickfix/HttpServer.h +78 -0
- data/ext/quickfix/Initiator.cpp +289 -0
- data/ext/quickfix/Initiator.h +149 -0
- data/ext/quickfix/Log.cpp +77 -0
- data/ext/quickfix/Log.h +179 -0
- data/ext/quickfix/Message.cpp +580 -0
- data/ext/quickfix/Message.h +370 -0
- data/ext/quickfix/MessageCracker.h +188 -0
- data/ext/quickfix/MessageSorters.cpp +105 -0
- data/ext/quickfix/MessageSorters.h +156 -0
- data/ext/quickfix/MessageStore.cpp +146 -0
- data/ext/quickfix/MessageStore.h +174 -0
- data/ext/quickfix/Mutex.h +131 -0
- data/ext/quickfix/MySQLConnection.h +194 -0
- data/ext/quickfix/MySQLLog.cpp +275 -0
- data/ext/quickfix/MySQLLog.h +145 -0
- data/ext/quickfix/MySQLStore.cpp +331 -0
- data/ext/quickfix/MySQLStore.h +142 -0
- data/ext/quickfix/NullStore.cpp +54 -0
- data/ext/quickfix/NullStore.h +99 -0
- data/ext/quickfix/OdbcConnection.h +266 -0
- data/ext/quickfix/OdbcLog.cpp +252 -0
- data/ext/quickfix/OdbcLog.h +117 -0
- data/ext/quickfix/OdbcStore.cpp +338 -0
- data/ext/quickfix/OdbcStore.h +113 -0
- data/ext/quickfix/PUGIXML_DOMDocument.cpp +112 -0
- data/ext/quickfix/PUGIXML_DOMDocument.h +81 -0
- data/ext/quickfix/Parser.cpp +103 -0
- data/ext/quickfix/Parser.h +57 -0
- data/ext/quickfix/PostgreSQLConnection.h +176 -0
- data/ext/quickfix/PostgreSQLLog.cpp +276 -0
- data/ext/quickfix/PostgreSQLLog.h +144 -0
- data/ext/quickfix/PostgreSQLStore.cpp +334 -0
- data/ext/quickfix/PostgreSQLStore.h +141 -0
- data/ext/quickfix/Queue.h +75 -0
- data/ext/quickfix/QuickfixRuby.cpp +252066 -0
- data/ext/quickfix/QuickfixRuby.h +34 -0
- data/ext/quickfix/Responder.h +43 -0
- data/ext/quickfix/Session.cpp +1487 -0
- data/ext/quickfix/Session.h +335 -0
- data/ext/quickfix/SessionFactory.cpp +274 -0
- data/ext/quickfix/SessionFactory.h +86 -0
- data/ext/quickfix/SessionID.h +170 -0
- data/ext/quickfix/SessionSettings.cpp +189 -0
- data/ext/quickfix/SessionSettings.h +171 -0
- data/ext/quickfix/SessionState.h +231 -0
- data/ext/quickfix/Settings.cpp +100 -0
- data/ext/quickfix/Settings.h +53 -0
- data/ext/quickfix/SharedArray.h +150 -0
- data/ext/quickfix/SocketAcceptor.cpp +222 -0
- data/ext/quickfix/SocketAcceptor.h +75 -0
- data/ext/quickfix/SocketConnection.cpp +238 -0
- data/ext/quickfix/SocketConnection.h +103 -0
- data/ext/quickfix/SocketConnector.cpp +116 -0
- data/ext/quickfix/SocketConnector.h +67 -0
- data/ext/quickfix/SocketInitiator.cpp +260 -0
- data/ext/quickfix/SocketInitiator.h +81 -0
- data/ext/quickfix/SocketMonitor.cpp +335 -0
- data/ext/quickfix/SocketMonitor.h +111 -0
- data/ext/quickfix/SocketServer.cpp +177 -0
- data/ext/quickfix/SocketServer.h +100 -0
- data/ext/quickfix/ThreadedSocketAcceptor.cpp +258 -0
- data/ext/quickfix/ThreadedSocketAcceptor.h +98 -0
- data/ext/quickfix/ThreadedSocketConnection.cpp +209 -0
- data/ext/quickfix/ThreadedSocketConnection.h +82 -0
- data/ext/quickfix/ThreadedSocketInitiator.cpp +268 -0
- data/ext/quickfix/ThreadedSocketInitiator.h +84 -0
- data/ext/quickfix/TimeRange.cpp +173 -0
- data/ext/quickfix/TimeRange.h +258 -0
- data/ext/quickfix/Utility.cpp +537 -0
- data/ext/quickfix/Utility.h +219 -0
- data/ext/quickfix/Values.h +62 -0
- data/ext/quickfix/config.h +0 -0
- data/ext/quickfix/config_windows.h +0 -0
- data/ext/quickfix/extconf.rb +12 -0
- data/ext/quickfix/index.h +37 -0
- data/ext/quickfix/pugiconfig.hpp +72 -0
- data/ext/quickfix/pugixml.cpp +10765 -0
- data/ext/quickfix/pugixml.hpp +1341 -0
- data/ext/quickfix/strptime.h +7 -0
- data/lib/quickfix40.rb +274 -0
- data/lib/quickfix41.rb +351 -0
- data/lib/quickfix42.rb +1184 -0
- data/lib/quickfix43.rb +3504 -0
- data/lib/quickfix44.rb +10721 -0
- data/lib/quickfix50.rb +13426 -0
- data/lib/quickfix50sp1.rb +15629 -0
- data/lib/quickfix50sp2.rb +17068 -0
- data/lib/quickfix_fields.rb +19853 -0
- data/lib/quickfix_ruby.rb +82 -0
- data/lib/quickfixt11.rb +70 -0
- data/spec/FIX40.xml +862 -0
- data/spec/FIX41.xml +1285 -0
- data/spec/FIX42.xml +2746 -0
- data/spec/FIX43.xml +4229 -0
- data/spec/FIX44.xml +6596 -0
- data/spec/FIX50.xml +8137 -0
- data/spec/FIX50SP1.xml +9496 -0
- data/spec/FIX50SP2.xml +10011 -0
- data/spec/FIXT11.xml +313 -0
- data/test/test_DataDictionaryTestCase.rb +268 -0
- data/test/test_DictionaryTestCase.rb +112 -0
- data/test/test_FieldBaseTestCase.rb +24 -0
- data/test/test_MessageTestCase.rb +368 -0
- data/test/test_SessionSettingsTestCase.rb +41 -0
- metadata +193 -0
|
@@ -0,0 +1,580 @@
|
|
|
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
|
+
|
|
35
|
+
Message::Message()
|
|
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
|
+
|
|
81
|
+
void Message::reverseRoute( const Header& header )
|
|
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 );
|
|
194
|
+
FieldMap::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;
|
|
227
|
+
FieldMap::iterator i;
|
|
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
|
+
|
|
250
|
+
FieldMap::g_iterator j;
|
|
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
|
+
{
|
|
279
|
+
FIELD::BeginString,
|
|
280
|
+
FIELD::BodyLength,
|
|
281
|
+
FIELD::MsgType
|
|
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:
|
|
409
|
+
case FIELD::OnBehalfOfCompID:
|
|
410
|
+
case FIELD::DeliverToCompID:
|
|
411
|
+
case FIELD::SecureDataLen:
|
|
412
|
+
case FIELD::MsgSeqNum:
|
|
413
|
+
case FIELD::SenderSubID:
|
|
414
|
+
case FIELD::SenderLocationID:
|
|
415
|
+
case FIELD::TargetSubID:
|
|
416
|
+
case FIELD::TargetLocationID:
|
|
417
|
+
case FIELD::OnBehalfOfSubID:
|
|
418
|
+
case FIELD::OnBehalfOfLocationID:
|
|
419
|
+
case FIELD::DeliverToSubID:
|
|
420
|
+
case FIELD::DeliverToLocationID:
|
|
421
|
+
case FIELD::PossDupFlag:
|
|
422
|
+
case FIELD::PossResend:
|
|
423
|
+
case FIELD::SendingTime:
|
|
424
|
+
case FIELD::OrigSendingTime:
|
|
425
|
+
case FIELD::XmlDataLen:
|
|
426
|
+
case FIELD::XmlData:
|
|
427
|
+
case FIELD::MessageEncoding:
|
|
428
|
+
case FIELD::LastMsgSeqNumProcessed:
|
|
429
|
+
case FIELD::OnBehalfOfSendingTime:
|
|
430
|
+
case FIELD::ApplVerID:
|
|
431
|
+
case FIELD::CstmApplVerID:
|
|
432
|
+
case FIELD::NoHops:
|
|
433
|
+
return true;
|
|
434
|
+
default:
|
|
435
|
+
return false;
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
bool Message::isHeaderField( const FieldBase& field,
|
|
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
|
+
{
|
|
451
|
+
case FIELD::SignatureLength:
|
|
452
|
+
case FIELD::Signature:
|
|
453
|
+
case FIELD::CheckSum:
|
|
454
|
+
return true;
|
|
455
|
+
default:
|
|
456
|
+
return false;
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
bool Message::isTrailerField( const FieldBase& field,
|
|
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
|
+
|
|
489
|
+
void Message::validate()
|
|
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
|
+
}
|