quickfix_ruby 1.14.3.1 → 1.15.1
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 +4 -4
- data/ext/quickfix/Acceptor.h +2 -0
- data/ext/quickfix/AtomicCount.h +82 -12
- data/ext/quickfix/DOMDocument.h +9 -7
- data/ext/quickfix/DataDictionary.cpp +77 -14
- data/ext/quickfix/DataDictionary.h +90 -16
- data/ext/quickfix/Dictionary.cpp +1 -2
- data/ext/quickfix/Exceptions.h +3 -5
- data/ext/quickfix/Field.h +83 -32
- data/ext/quickfix/FieldConvertors.cpp +93 -0
- data/ext/quickfix/FieldConvertors.h +129 -275
- data/ext/quickfix/FieldMap.cpp +53 -13
- data/ext/quickfix/FieldMap.h +200 -62
- data/ext/quickfix/FieldTypes.cpp +10 -10
- data/ext/quickfix/FieldTypes.h +293 -44
- data/ext/quickfix/FileLog.cpp +6 -10
- data/ext/quickfix/FileLog.h +4 -10
- data/ext/quickfix/FileStore.cpp +19 -6
- data/ext/quickfix/FileStore.h +4 -0
- data/ext/quickfix/FixFieldNumbers.h +1462 -1461
- data/ext/quickfix/FixFields.h +1462 -1461
- data/ext/quickfix/FixValues.h +3230 -3227
- data/ext/quickfix/HttpConnection.cpp +1 -1
- data/ext/quickfix/Initiator.cpp +7 -1
- data/ext/quickfix/Initiator.h +2 -0
- data/ext/quickfix/Log.h +6 -12
- data/ext/quickfix/Message.cpp +186 -57
- data/ext/quickfix/Message.h +109 -47
- data/ext/quickfix/MySQLConnection.h +1 -1
- data/ext/quickfix/PostgreSQLConnection.h +1 -1
- data/ext/quickfix/QuickfixRuby.cpp +79141 -77959
- data/ext/quickfix/QuickfixRuby.h +1 -1
- data/ext/quickfix/SSLSocketAcceptor.cpp +410 -0
- data/ext/quickfix/SSLSocketAcceptor.h +185 -0
- data/ext/quickfix/SSLSocketConnection.cpp +427 -0
- data/ext/quickfix/SSLSocketConnection.h +206 -0
- data/ext/quickfix/SSLSocketInitiator.cpp +485 -0
- data/ext/quickfix/SSLSocketInitiator.h +196 -0
- data/ext/quickfix/Session.cpp +113 -20
- data/ext/quickfix/Session.h +18 -4
- data/ext/quickfix/SessionFactory.cpp +10 -3
- data/ext/quickfix/SessionSettings.cpp +5 -3
- data/ext/quickfix/SessionSettings.h +97 -5
- data/ext/quickfix/Settings.cpp +72 -2
- data/ext/quickfix/Settings.h +3 -0
- data/ext/quickfix/SharedArray.h +140 -6
- data/ext/quickfix/SocketConnection.cpp +2 -2
- data/ext/quickfix/SocketConnector.cpp +5 -2
- data/ext/quickfix/SocketConnector.h +3 -2
- data/ext/quickfix/SocketInitiator.cpp +28 -4
- data/ext/quickfix/SocketInitiator.h +1 -1
- data/ext/quickfix/SocketMonitor.cpp +5 -5
- data/ext/quickfix/ThreadedSSLSocketAcceptor.cpp +455 -0
- data/ext/quickfix/ThreadedSSLSocketAcceptor.h +217 -0
- data/ext/quickfix/ThreadedSSLSocketConnection.cpp +404 -0
- data/ext/quickfix/ThreadedSSLSocketConnection.h +189 -0
- data/ext/quickfix/ThreadedSSLSocketInitiator.cpp +469 -0
- data/ext/quickfix/ThreadedSSLSocketInitiator.h +201 -0
- data/ext/quickfix/ThreadedSocketAcceptor.cpp +5 -1
- data/ext/quickfix/ThreadedSocketConnection.cpp +8 -2
- data/ext/quickfix/ThreadedSocketConnection.h +4 -1
- data/ext/quickfix/ThreadedSocketInitiator.cpp +24 -4
- data/ext/quickfix/ThreadedSocketInitiator.h +1 -1
- data/ext/quickfix/Utility.cpp +23 -1
- data/ext/quickfix/Utility.h +28 -2
- data/ext/quickfix/UtilitySSL.cpp +1733 -0
- data/ext/quickfix/UtilitySSL.h +277 -0
- data/ext/quickfix/config-all.h +10 -0
- data/ext/quickfix/dirent_windows.h +838 -0
- data/ext/quickfix/double-conversion/bignum-dtoa.cc +641 -0
- data/ext/quickfix/double-conversion/bignum-dtoa.h +84 -0
- data/ext/quickfix/double-conversion/bignum.cc +766 -0
- data/ext/quickfix/double-conversion/bignum.h +144 -0
- data/ext/quickfix/double-conversion/cached-powers.cc +176 -0
- data/ext/quickfix/double-conversion/cached-powers.h +64 -0
- data/ext/quickfix/double-conversion/diy-fp.cc +57 -0
- data/ext/quickfix/double-conversion/diy-fp.h +118 -0
- data/ext/quickfix/double-conversion/double-conversion.cc +994 -0
- data/ext/quickfix/double-conversion/double-conversion.h +543 -0
- data/ext/quickfix/double-conversion/fast-dtoa.cc +665 -0
- data/ext/quickfix/double-conversion/fast-dtoa.h +88 -0
- data/ext/quickfix/double-conversion/fixed-dtoa.cc +404 -0
- data/ext/quickfix/double-conversion/fixed-dtoa.h +56 -0
- data/ext/quickfix/double-conversion/ieee.h +402 -0
- data/ext/quickfix/double-conversion/strtod.cc +557 -0
- data/ext/quickfix/double-conversion/strtod.h +45 -0
- data/ext/quickfix/double-conversion/utils.h +372 -0
- data/ext/quickfix/stdint_msvc.h +254 -0
- data/lib/quickfix44.rb +3329 -10
- data/lib/quickfix50.rb +6649 -81
- data/lib/quickfix50sp1.rb +8054 -142
- data/lib/quickfix50sp2.rb +10900 -234
- data/lib/quickfix_fields.rb +7662 -7649
- data/spec/FIX40.xml +28 -28
- data/spec/FIX41.xml +29 -29
- data/spec/FIX42.xml +47 -47
- data/spec/FIX43.xml +148 -148
- data/spec/FIX44.xml +1078 -1081
- data/spec/FIX50.xml +1292 -1289
- data/spec/FIX50SP1.xml +1811 -1802
- data/spec/FIX50SP2.xml +1948 -1939
- data/spec/FIXT11.xml +5 -8
- data/test/test_FieldBaseTestCase.rb +1 -1
- data/test/test_MessageTestCase.rb +2 -2
- metadata +42 -6
data/ext/quickfix/Dictionary.cpp
CHANGED
|
@@ -87,7 +87,7 @@ throw( ConfigError, FieldConvertError )
|
|
|
87
87
|
try
|
|
88
88
|
{
|
|
89
89
|
std::string value = getString(key);
|
|
90
|
-
if( value.size() < 2 ) throw FieldConvertError(
|
|
90
|
+
if( value.size() < 2 ) throw FieldConvertError();
|
|
91
91
|
std::string abbr = value.substr(0, 2);
|
|
92
92
|
std::transform( abbr.begin(), abbr.end(), abbr.begin(), tolower );
|
|
93
93
|
if( abbr == "su" ) return 1;
|
|
@@ -97,7 +97,6 @@ throw( ConfigError, FieldConvertError )
|
|
|
97
97
|
if( abbr == "th" ) return 5;
|
|
98
98
|
if( abbr == "fr" ) return 6;
|
|
99
99
|
if( abbr == "sa" ) return 7;
|
|
100
|
-
if( value.size() < 2 ) throw FieldConvertError(0);
|
|
101
100
|
}
|
|
102
101
|
catch ( FieldConvertError& )
|
|
103
102
|
{
|
data/ext/quickfix/Exceptions.h
CHANGED
|
@@ -250,22 +250,20 @@ struct SocketException : public Exception
|
|
|
250
250
|
SocketException( const std::string& what )
|
|
251
251
|
: Exception( "Socket Error", what ) {}
|
|
252
252
|
|
|
253
|
-
std::string errorToWhat()
|
|
253
|
+
static std::string errorToWhat()
|
|
254
254
|
{
|
|
255
255
|
#ifdef _MSC_VER
|
|
256
|
-
error = WSAGetLastError();
|
|
256
|
+
int error = WSAGetLastError();
|
|
257
257
|
char buffer[2048];
|
|
258
258
|
FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
|
|
259
259
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
260
260
|
buffer, 2048, NULL );
|
|
261
261
|
return buffer;
|
|
262
262
|
#else
|
|
263
|
-
error = errno;
|
|
263
|
+
int error = errno;
|
|
264
264
|
return strerror( error );
|
|
265
265
|
#endif
|
|
266
266
|
}
|
|
267
|
-
|
|
268
|
-
int error;
|
|
269
267
|
};
|
|
270
268
|
|
|
271
269
|
/// Socket send operation failed
|
data/ext/quickfix/Field.h
CHANGED
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
#include "FieldTypes.h"
|
|
34
34
|
#include "Utility.h"
|
|
35
35
|
|
|
36
|
+
#if defined(__SUNPRO_CC)
|
|
37
|
+
#include <algorithm>
|
|
38
|
+
#endif
|
|
39
|
+
|
|
36
40
|
namespace FIX
|
|
37
41
|
{
|
|
38
42
|
/**
|
|
@@ -73,30 +77,62 @@ class FieldBase
|
|
|
73
77
|
friend class Message;
|
|
74
78
|
|
|
75
79
|
/// Constructor which also calculates field metrics
|
|
76
|
-
FieldBase( int
|
|
80
|
+
FieldBase( int tag,
|
|
77
81
|
std::string::const_iterator valueStart,
|
|
78
82
|
std::string::const_iterator valueEnd,
|
|
79
83
|
std::string::const_iterator tagStart,
|
|
80
84
|
std::string::const_iterator tagEnd )
|
|
81
|
-
:
|
|
85
|
+
: m_tag( tag )
|
|
82
86
|
, m_string( valueStart, valueEnd )
|
|
83
87
|
, m_metrics( calculateMetrics( tagStart, tagEnd ) )
|
|
84
88
|
{}
|
|
85
89
|
|
|
86
90
|
public:
|
|
87
|
-
FieldBase( int
|
|
88
|
-
:
|
|
91
|
+
FieldBase( int tag, const std::string& string )
|
|
92
|
+
: m_tag( tag ), m_string(string), m_metrics( no_metrics() )
|
|
89
93
|
{}
|
|
90
94
|
|
|
91
95
|
virtual ~FieldBase() {}
|
|
92
96
|
|
|
93
|
-
|
|
97
|
+
FieldBase( const FieldBase& rhs )
|
|
98
|
+
: m_tag( rhs.getTag() )
|
|
99
|
+
, m_string( rhs.m_string )
|
|
100
|
+
, m_metrics( rhs.m_metrics )
|
|
101
|
+
{
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
FieldBase& operator=( const FieldBase& rhs)
|
|
106
|
+
{
|
|
107
|
+
m_tag = rhs.getTag();
|
|
108
|
+
m_string = rhs.m_string;
|
|
109
|
+
m_metrics = rhs.m_metrics;
|
|
110
|
+
m_data.clear();
|
|
111
|
+
|
|
112
|
+
return *this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
void swap( FieldBase& rhs )
|
|
94
116
|
{
|
|
95
|
-
|
|
117
|
+
std::swap( m_tag, rhs.m_tag );
|
|
118
|
+
std::swap( m_metrics, rhs.m_metrics );
|
|
119
|
+
m_string.swap( rhs.m_string );
|
|
120
|
+
m_data.swap( rhs.m_data );
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void setTag( int tag )
|
|
124
|
+
{
|
|
125
|
+
m_tag = tag;
|
|
96
126
|
m_metrics = no_metrics();
|
|
97
127
|
m_data.clear();
|
|
98
128
|
}
|
|
99
129
|
|
|
130
|
+
/// @deprecated Use setTag
|
|
131
|
+
void setField( int field )
|
|
132
|
+
{
|
|
133
|
+
setTag( field );
|
|
134
|
+
}
|
|
135
|
+
|
|
100
136
|
void setString( const std::string& string )
|
|
101
137
|
{
|
|
102
138
|
m_string = string;
|
|
@@ -105,8 +141,12 @@ public:
|
|
|
105
141
|
}
|
|
106
142
|
|
|
107
143
|
/// Get the fields integer tag.
|
|
144
|
+
int getTag() const
|
|
145
|
+
{ return m_tag; }
|
|
146
|
+
|
|
147
|
+
/// @deprecated Use getTag
|
|
108
148
|
int getField() const
|
|
109
|
-
{ return
|
|
149
|
+
{ return getTag(); }
|
|
110
150
|
|
|
111
151
|
/// Get the string representation of the fields value.
|
|
112
152
|
const std::string& getString() const
|
|
@@ -137,7 +177,7 @@ public:
|
|
|
137
177
|
|
|
138
178
|
/// Compares fields based on their tag numbers
|
|
139
179
|
bool operator < ( const FieldBase& field ) const
|
|
140
|
-
{ return
|
|
180
|
+
{ return m_tag < field.m_tag; }
|
|
141
181
|
|
|
142
182
|
private:
|
|
143
183
|
|
|
@@ -151,16 +191,16 @@ private:
|
|
|
151
191
|
/// Serializes string representation of the Field to input string
|
|
152
192
|
void encodeTo( std::string& result ) const
|
|
153
193
|
{
|
|
154
|
-
size_t tagLength = FIX::number_of_symbols_in(
|
|
155
|
-
size_t totalLength = tagLength + m_string.length() +
|
|
194
|
+
size_t tagLength = FIX::number_of_symbols_in( m_tag );
|
|
195
|
+
size_t totalLength = tagLength + m_string.length() + 2;
|
|
156
196
|
|
|
157
197
|
result.resize( totalLength );
|
|
158
198
|
|
|
159
199
|
char * buf = (char*)result.c_str();
|
|
160
|
-
FIX::integer_to_string( buf, tagLength,
|
|
200
|
+
FIX::integer_to_string( buf, tagLength, m_tag );
|
|
161
201
|
|
|
162
|
-
buf[tagLength
|
|
163
|
-
memcpy( buf + tagLength, m_string.data(), m_string.length() );
|
|
202
|
+
buf[tagLength] = '=';
|
|
203
|
+
memcpy( buf + tagLength + 1, m_string.data(), m_string.length() );
|
|
164
204
|
buf[totalLength - 1] = '\001';
|
|
165
205
|
}
|
|
166
206
|
|
|
@@ -178,7 +218,13 @@ private:
|
|
|
178
218
|
for ( std::string::const_iterator str = start; str != end; ++str )
|
|
179
219
|
checksum += (unsigned char)( *str );
|
|
180
220
|
|
|
221
|
+
#if defined(__SUNPRO_CC)
|
|
222
|
+
std::ptrdiff_t d;
|
|
223
|
+
std::distance(start, end, d);
|
|
224
|
+
return field_metrics( d, checksum );
|
|
225
|
+
#else
|
|
181
226
|
return field_metrics( std::distance( start, end ), checksum );
|
|
227
|
+
#endif
|
|
182
228
|
}
|
|
183
229
|
|
|
184
230
|
static field_metrics calculateMetrics( const std::string& field )
|
|
@@ -186,7 +232,7 @@ private:
|
|
|
186
232
|
return calculateMetrics( field.begin(), field.end() );
|
|
187
233
|
}
|
|
188
234
|
|
|
189
|
-
int
|
|
235
|
+
int m_tag;
|
|
190
236
|
std::string m_string;
|
|
191
237
|
mutable std::string m_data;
|
|
192
238
|
mutable field_metrics m_metrics;
|
|
@@ -200,6 +246,11 @@ inline std::ostream& operator <<
|
|
|
200
246
|
return stream;
|
|
201
247
|
}
|
|
202
248
|
|
|
249
|
+
inline void swap( FieldBase& lhs, FieldBase& rhs )
|
|
250
|
+
{
|
|
251
|
+
lhs.swap( rhs );
|
|
252
|
+
}
|
|
253
|
+
|
|
203
254
|
/**
|
|
204
255
|
* MSC doesn't support partial template specialization so we have this.
|
|
205
256
|
* this is here to provide equality checking against native char arrays.
|
|
@@ -323,7 +374,7 @@ public:
|
|
|
323
374
|
{ try
|
|
324
375
|
{ return CharConvertor::convert( getString() ); }
|
|
325
376
|
catch( FieldConvertError& )
|
|
326
|
-
{ throw IncorrectDataFormat(
|
|
377
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
327
378
|
operator char() const
|
|
328
379
|
{ return getValue(); }
|
|
329
380
|
};
|
|
@@ -343,7 +394,7 @@ public:
|
|
|
343
394
|
{ try
|
|
344
395
|
{ return DoubleConvertor::convert( getString() ); }
|
|
345
396
|
catch( FieldConvertError& )
|
|
346
|
-
{ throw IncorrectDataFormat(
|
|
397
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
347
398
|
operator double() const
|
|
348
399
|
{ return getValue(); }
|
|
349
400
|
};
|
|
@@ -363,7 +414,7 @@ public:
|
|
|
363
414
|
{ try
|
|
364
415
|
{ return IntConvertor::convert( getString() ); }
|
|
365
416
|
catch( FieldConvertError& )
|
|
366
|
-
{ throw IncorrectDataFormat(
|
|
417
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
367
418
|
operator const int() const
|
|
368
419
|
{ return getValue(); }
|
|
369
420
|
};
|
|
@@ -383,7 +434,7 @@ public:
|
|
|
383
434
|
{ try
|
|
384
435
|
{ return BoolConvertor::convert( getString() ); }
|
|
385
436
|
catch( FieldConvertError& )
|
|
386
|
-
{ throw IncorrectDataFormat(
|
|
437
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
387
438
|
operator bool() const
|
|
388
439
|
{ return getValue(); }
|
|
389
440
|
};
|
|
@@ -392,10 +443,10 @@ public:
|
|
|
392
443
|
class UtcTimeStampField : public FieldBase
|
|
393
444
|
{
|
|
394
445
|
public:
|
|
395
|
-
explicit UtcTimeStampField( int field, const UtcTimeStamp& data,
|
|
396
|
-
: FieldBase( field, UtcTimeStampConvertor::convert( data,
|
|
397
|
-
UtcTimeStampField( int field,
|
|
398
|
-
: FieldBase( field, UtcTimeStampConvertor::convert( UtcTimeStamp(),
|
|
446
|
+
explicit UtcTimeStampField( int field, const UtcTimeStamp& data, int precision = 0 )
|
|
447
|
+
: FieldBase( field, UtcTimeStampConvertor::convert( data, precision ) ) {}
|
|
448
|
+
UtcTimeStampField( int field, int precision = 0 )
|
|
449
|
+
: FieldBase( field, UtcTimeStampConvertor::convert( UtcTimeStamp(), precision ) ) {}
|
|
399
450
|
|
|
400
451
|
void setValue( const UtcTimeStamp& value )
|
|
401
452
|
{ setString( UtcTimeStampConvertor::convert( value ) ); }
|
|
@@ -403,7 +454,7 @@ public:
|
|
|
403
454
|
{ try
|
|
404
455
|
{ return UtcTimeStampConvertor::convert( getString() ); }
|
|
405
456
|
catch( FieldConvertError& )
|
|
406
|
-
{ throw IncorrectDataFormat(
|
|
457
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
407
458
|
operator UtcTimeStamp() const
|
|
408
459
|
{ return getValue(); }
|
|
409
460
|
|
|
@@ -430,7 +481,7 @@ public:
|
|
|
430
481
|
{ try
|
|
431
482
|
{ return UtcDateConvertor::convert( getString() ); }
|
|
432
483
|
catch( FieldConvertError& )
|
|
433
|
-
{ throw IncorrectDataFormat(
|
|
484
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
434
485
|
operator UtcDate() const
|
|
435
486
|
{ return getValue(); }
|
|
436
487
|
|
|
@@ -446,10 +497,10 @@ public:
|
|
|
446
497
|
class UtcTimeOnlyField : public FieldBase
|
|
447
498
|
{
|
|
448
499
|
public:
|
|
449
|
-
explicit UtcTimeOnlyField( int field, const UtcTimeOnly& data,
|
|
450
|
-
: FieldBase( field, UtcTimeOnlyConvertor::convert( data,
|
|
451
|
-
UtcTimeOnlyField( int field,
|
|
452
|
-
: FieldBase( field, UtcTimeOnlyConvertor::convert( UtcTimeOnly(),
|
|
500
|
+
explicit UtcTimeOnlyField( int field, const UtcTimeOnly& data, int precision = 0 )
|
|
501
|
+
: FieldBase( field, UtcTimeOnlyConvertor::convert( data, precision ) ) {}
|
|
502
|
+
UtcTimeOnlyField( int field, int precision = 0 )
|
|
503
|
+
: FieldBase( field, UtcTimeOnlyConvertor::convert( UtcTimeOnly(), precision ) ) {}
|
|
453
504
|
|
|
454
505
|
void setValue( const UtcTimeOnly& value )
|
|
455
506
|
{ setString( UtcTimeOnlyConvertor::convert( value ) ); }
|
|
@@ -457,7 +508,7 @@ public:
|
|
|
457
508
|
{ try
|
|
458
509
|
{ return UtcTimeOnlyConvertor::convert( getString() ); }
|
|
459
510
|
catch( FieldConvertError& )
|
|
460
|
-
{ throw IncorrectDataFormat(
|
|
511
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
461
512
|
operator UtcTimeOnly() const
|
|
462
513
|
{ return getValue(); }
|
|
463
514
|
|
|
@@ -484,7 +535,7 @@ public:
|
|
|
484
535
|
{ try
|
|
485
536
|
{ return CheckSumConvertor::convert( getString() ); }
|
|
486
537
|
catch( FieldConvertError& )
|
|
487
|
-
{ throw IncorrectDataFormat(
|
|
538
|
+
{ throw IncorrectDataFormat( getTag(), getString() ); } }
|
|
488
539
|
operator const int() const
|
|
489
540
|
{ return getValue(); }
|
|
490
541
|
};
|
|
@@ -529,9 +580,9 @@ DEFINE_FIELD_CLASS_NUM(NAME, TOK, TYPE, DEPRECATED_FIELD::NAME)
|
|
|
529
580
|
#define DEFINE_FIELD_TIMECLASS_NUM( NAME, TOK, TYPE, NUM ) \
|
|
530
581
|
class NAME : public TOK##Field { public: \
|
|
531
582
|
NAME() : TOK##Field(NUM, false) {} \
|
|
532
|
-
NAME(
|
|
583
|
+
NAME(int precision) : TOK##Field(NUM, precision) {} \
|
|
533
584
|
NAME(const TYPE& value) : TOK##Field(NUM, value) {} \
|
|
534
|
-
NAME(const TYPE& value,
|
|
585
|
+
NAME(const TYPE& value, int precision) : TOK##Field(NUM, value, precision) {} \
|
|
535
586
|
}
|
|
536
587
|
|
|
537
588
|
#define DEFINE_FIELD_TIMECLASS( NAME, TOK, TYPE ) \
|
|
@@ -0,0 +1,93 @@
|
|
|
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 <math.h>
|
|
27
|
+
#include "FieldConvertors.h"
|
|
28
|
+
#include <math.h>
|
|
29
|
+
|
|
30
|
+
namespace FIX
|
|
31
|
+
{
|
|
32
|
+
|
|
33
|
+
// we include "double-conversion" project in FIX namespace
|
|
34
|
+
// to avoid linking errors if quickfix is linked statically
|
|
35
|
+
// and "double-conversion" is already used by target project
|
|
36
|
+
|
|
37
|
+
#include "double-conversion/diy-fp.cc"
|
|
38
|
+
#include "double-conversion/fixed-dtoa.cc"
|
|
39
|
+
#include "double-conversion/bignum.cc"
|
|
40
|
+
#include "double-conversion/bignum-dtoa.cc"
|
|
41
|
+
#include "double-conversion/cached-powers.cc"
|
|
42
|
+
#include "double-conversion/fast-dtoa.cc"
|
|
43
|
+
#include "double-conversion/strtod.cc"
|
|
44
|
+
#include "double-conversion/double-conversion.cc"
|
|
45
|
+
|
|
46
|
+
static double_conversion::DoubleToStringConverter g_dtoa_converter(
|
|
47
|
+
double_conversion::DoubleToStringConverter::NO_FLAGS,
|
|
48
|
+
"INF",
|
|
49
|
+
"NAN",
|
|
50
|
+
'e',
|
|
51
|
+
-DoubleConvertor::SIGNIFICANT_DIGITS,
|
|
52
|
+
DoubleConvertor::SIGNIFICANT_DIGITS,
|
|
53
|
+
DoubleConvertor::SIGNIFICANT_DIGITS - 1,
|
|
54
|
+
0);
|
|
55
|
+
|
|
56
|
+
static double_conversion::StringToDoubleConverter g_atod_converter(
|
|
57
|
+
double_conversion::StringToDoubleConverter::NO_FLAGS,
|
|
58
|
+
std::numeric_limits<double>::quiet_NaN(),
|
|
59
|
+
std::numeric_limits<double>::quiet_NaN(),
|
|
60
|
+
"INF",
|
|
61
|
+
"NAN");
|
|
62
|
+
|
|
63
|
+
double DoubleConvertor::fast_strtod( const char * buffer, int size, int * processed_chars )
|
|
64
|
+
{
|
|
65
|
+
return g_atod_converter.StringToDouble( buffer, size, processed_chars );
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
int DoubleConvertor::fast_dtoa( char * buffer, int size, double value )
|
|
69
|
+
{
|
|
70
|
+
double_conversion::StringBuilder builder( buffer, size );
|
|
71
|
+
if( !g_dtoa_converter.ToPrecision( value, DoubleConvertor::SIGNIFICANT_DIGITS, &builder ) )
|
|
72
|
+
{
|
|
73
|
+
builder.Reset();
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
builder.TrimTrailingZeros();
|
|
78
|
+
return builder.position();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
int DoubleConvertor::fast_fixed_dtoa( char * buffer, int size, double value )
|
|
82
|
+
{
|
|
83
|
+
double_conversion::StringBuilder builder( buffer, size );
|
|
84
|
+
if( !g_dtoa_converter.ToFixed( value, DoubleConvertor::SIGNIFICANT_DIGITS, &builder ) )
|
|
85
|
+
{
|
|
86
|
+
builder.Reset();
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return builder.position();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
}
|
|
@@ -22,14 +22,20 @@
|
|
|
22
22
|
#ifndef FIX_FIELDCONVERTORS_H
|
|
23
23
|
#define FIX_FIELDCONVERTORS_H
|
|
24
24
|
|
|
25
|
+
#ifdef _MSC_VER
|
|
26
|
+
#pragma warning( disable: 4146 )
|
|
27
|
+
#endif
|
|
28
|
+
|
|
25
29
|
#include "FieldTypes.h"
|
|
26
30
|
#include "Exceptions.h"
|
|
27
31
|
#include "Utility.h"
|
|
32
|
+
#include "config-all.h"
|
|
28
33
|
#include <string>
|
|
29
34
|
#include <sstream>
|
|
30
35
|
#include <iomanip>
|
|
31
36
|
#include <cstdio>
|
|
32
37
|
#include <limits>
|
|
38
|
+
#include <iterator>
|
|
33
39
|
|
|
34
40
|
namespace FIX
|
|
35
41
|
{
|
|
@@ -37,7 +43,7 @@ namespace FIX
|
|
|
37
43
|
typedef int signed_int;
|
|
38
44
|
typedef unsigned int unsigned_int;
|
|
39
45
|
|
|
40
|
-
#define UNSIGNED_VALUE_OF( x )
|
|
46
|
+
#define UNSIGNED_VALUE_OF( x ) ( ( x < 0 ) ? -unsigned_int(x) : unsigned_int(x) )
|
|
41
47
|
|
|
42
48
|
#define IS_SPACE( x ) ( x == ' ' )
|
|
43
49
|
#define IS_DIGIT( x ) ( unsigned_int( x - '0' ) < 10 )
|
|
@@ -95,22 +101,21 @@ inline char* integer_to_string( char* buf, const size_t len, signed_int t )
|
|
|
95
101
|
const bool isNegative = t < 0;
|
|
96
102
|
char* p = buf + len;
|
|
97
103
|
|
|
98
|
-
*--p = '\0';
|
|
99
|
-
|
|
100
104
|
unsigned_int number = UNSIGNED_VALUE_OF( t );
|
|
101
105
|
|
|
102
106
|
while( number > 99 )
|
|
103
107
|
{
|
|
104
108
|
unsigned_int pos = number % 100;
|
|
105
109
|
number /= 100;
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
|
|
111
|
+
*--p = digit_pairs[2 * pos + 1];
|
|
112
|
+
*--p = digit_pairs[2 * pos];
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
if( number > 9 )
|
|
111
116
|
{
|
|
112
|
-
p
|
|
113
|
-
|
|
117
|
+
*--p = digit_pairs[2 * number + 1];
|
|
118
|
+
*--p = digit_pairs[2 * number];
|
|
114
119
|
}
|
|
115
120
|
else
|
|
116
121
|
{
|
|
@@ -125,16 +130,10 @@ inline char* integer_to_string( char* buf, const size_t len, signed_int t )
|
|
|
125
130
|
|
|
126
131
|
inline char* integer_to_string_padded
|
|
127
132
|
( char* buf, const size_t len, signed_int t,
|
|
128
|
-
const size_t width = 0,
|
|
129
133
|
const char paddingChar = '0')
|
|
130
134
|
{
|
|
131
135
|
char* p = integer_to_string( buf, len, t );
|
|
132
|
-
|
|
133
|
-
return p;
|
|
134
|
-
|
|
135
|
-
const char* stop_p = buf + len - width - 1;
|
|
136
|
-
if( stop_p < buf ) stop_p = buf;
|
|
137
|
-
while( p > stop_p )
|
|
136
|
+
while( p > buf )
|
|
138
137
|
*--p = paddingChar;
|
|
139
138
|
return p;
|
|
140
139
|
}
|
|
@@ -155,10 +154,10 @@ struct IntConvertor
|
|
|
155
154
|
{
|
|
156
155
|
// buffer is big enough for significant digits and extra digit,
|
|
157
156
|
// minus and null
|
|
158
|
-
char buffer[std::numeric_limits<signed_int>::digits10 +
|
|
157
|
+
char buffer[std::numeric_limits<signed_int>::digits10 + 2];
|
|
159
158
|
const char* const start
|
|
160
159
|
= integer_to_string( buffer, sizeof (buffer), value );
|
|
161
|
-
return std::string( start, buffer + sizeof (buffer) - start
|
|
160
|
+
return std::string( start, buffer + sizeof (buffer) - start );
|
|
162
161
|
}
|
|
163
162
|
|
|
164
163
|
static bool convert(
|
|
@@ -187,7 +186,7 @@ struct IntConvertor
|
|
|
187
186
|
} while ( ++str != end );
|
|
188
187
|
|
|
189
188
|
if( isNegative )
|
|
190
|
-
x = -x;
|
|
189
|
+
x = -unsigned_int(x);
|
|
191
190
|
|
|
192
191
|
result = x;
|
|
193
192
|
return true;
|
|
@@ -207,70 +206,6 @@ struct IntConvertor
|
|
|
207
206
|
else
|
|
208
207
|
return result;
|
|
209
208
|
}
|
|
210
|
-
|
|
211
|
-
/// Converts only positive number e.g. FIX field ID: [1 ... 2147483647]
|
|
212
|
-
/// No leading whitespace/zero/plus/sign symbols allowed
|
|
213
|
-
/// Value is fixed to not make difference between 32bit and 64bit code
|
|
214
|
-
static bool convertPositive(
|
|
215
|
-
std::string::const_iterator str,
|
|
216
|
-
std::string::const_iterator end,
|
|
217
|
-
signed_int& result )
|
|
218
|
-
{
|
|
219
|
-
const int MAX_VALUE = 2147483647; // max value for 32-bit signed integer
|
|
220
|
-
const int HIGH_MARK = MAX_VALUE / 10;
|
|
221
|
-
const unsigned_int STOP_SYMBOL = MAX_VALUE % 10;
|
|
222
|
-
const std::size_t MAX_DIGITS = 10; // integer can hold up to 10 digits
|
|
223
|
-
|
|
224
|
-
const std::size_t length = std::distance( str, end );
|
|
225
|
-
if( length < 1 || length > MAX_DIGITS)
|
|
226
|
-
return false;
|
|
227
|
-
|
|
228
|
-
if( length == MAX_DIGITS )
|
|
229
|
-
{
|
|
230
|
-
end = str;
|
|
231
|
-
std::advance( end, length - 1 );
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const unsigned_int ch = *str - '1';
|
|
235
|
-
if( ch > 8 )
|
|
236
|
-
return false;
|
|
237
|
-
|
|
238
|
-
unsigned_int x = 0;
|
|
239
|
-
|
|
240
|
-
do
|
|
241
|
-
{
|
|
242
|
-
const unsigned_int c = *str - '0';
|
|
243
|
-
if( c > 9 ) return false;
|
|
244
|
-
x = 10 * x + c;
|
|
245
|
-
} while( ++str < end );
|
|
246
|
-
|
|
247
|
-
// complete overflow condition check and value calculation
|
|
248
|
-
// this saves about 25% of speed when executed out of the main loop
|
|
249
|
-
if( length == MAX_DIGITS )
|
|
250
|
-
{
|
|
251
|
-
if( x > (unsigned int)HIGH_MARK )
|
|
252
|
-
return false;
|
|
253
|
-
|
|
254
|
-
const unsigned_int c = *str - '0';
|
|
255
|
-
if( x == (unsigned int)HIGH_MARK && c > STOP_SYMBOL )
|
|
256
|
-
return false;
|
|
257
|
-
|
|
258
|
-
x = 10 * x + c;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
result = x;
|
|
262
|
-
return true;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
static signed_int convertPositive( const std::string& value )
|
|
266
|
-
throw( FieldConvertError )
|
|
267
|
-
{
|
|
268
|
-
signed_int result = 0;
|
|
269
|
-
if( !convertPositive( value.begin(), value.end(), result ) )
|
|
270
|
-
throw FieldConvertError(value);
|
|
271
|
-
else
|
|
272
|
-
return result;
|
|
273
|
-
}
|
|
274
209
|
};
|
|
275
210
|
|
|
276
211
|
/// Converts checksum to/from a string
|
|
@@ -280,12 +215,12 @@ struct CheckSumConvertor
|
|
|
280
215
|
throw( FieldConvertError )
|
|
281
216
|
{
|
|
282
217
|
if ( value > 255 || value < 0 ) throw FieldConvertError();
|
|
283
|
-
char result[
|
|
284
|
-
if( integer_to_string_padded(result, sizeof(result), value
|
|
218
|
+
char result[3];
|
|
219
|
+
if( integer_to_string_padded(result, sizeof(result), value) != result )
|
|
285
220
|
{
|
|
286
221
|
throw FieldConvertError();
|
|
287
222
|
}
|
|
288
|
-
return std::string( result,
|
|
223
|
+
return std::string( result, sizeof( result ) );
|
|
289
224
|
}
|
|
290
225
|
|
|
291
226
|
static bool convert( const std::string& value, int& result )
|
|
@@ -306,107 +241,28 @@ struct DoubleConvertor
|
|
|
306
241
|
|
|
307
242
|
private:
|
|
308
243
|
|
|
309
|
-
|
|
310
|
-
Executes about 5x faster than standard MSCRT library atof().
|
|
311
|
-
An attractive alternative if the number of calls is in the millions.
|
|
312
|
-
Assumes input is a proper integer, fraction, or scientific format.
|
|
313
|
-
Matches library atof() to 15 digits (except at extreme exponents).
|
|
314
|
-
Follows atof() precedent of essentially no error checking.
|
|
315
|
-
09-May-2009 Tom Van Baak (tvb) www.LeapSecond.com */
|
|
316
|
-
static double fast_atof (const char *p)
|
|
317
|
-
{
|
|
318
|
-
bool frac(false);
|
|
319
|
-
double sign(1.), value(0.), scale(1.);
|
|
320
|
-
|
|
321
|
-
while (IS_SPACE(*p))
|
|
322
|
-
++p;
|
|
323
|
-
|
|
324
|
-
// Get sign, if any.
|
|
325
|
-
if (*p == '-')
|
|
326
|
-
{
|
|
327
|
-
sign = -1.;
|
|
328
|
-
++p;
|
|
329
|
-
}
|
|
330
|
-
else if (*p == '+')
|
|
331
|
-
++p;
|
|
332
|
-
|
|
333
|
-
// Get digits before decimal point or exponent, if any.
|
|
334
|
-
while (IS_DIGIT(*p))
|
|
335
|
-
{
|
|
336
|
-
value = value * 10. + (*p - '0');
|
|
337
|
-
++p;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Get digits after decimal point, if any.
|
|
341
|
-
if (*p == '.')
|
|
342
|
-
{
|
|
343
|
-
++p;
|
|
344
|
-
double pow10(10.);
|
|
345
|
-
while (IS_DIGIT(*p))
|
|
346
|
-
{
|
|
347
|
-
value += (*p - '0') / pow10;
|
|
348
|
-
pow10 *= 10.;
|
|
349
|
-
++p;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Handle exponent, if any.
|
|
354
|
-
if (toupper(*p) == 'E')
|
|
355
|
-
{
|
|
356
|
-
unsigned int expon(0);
|
|
357
|
-
++p;
|
|
358
|
-
|
|
359
|
-
// Get sign of exponent, if any.
|
|
360
|
-
if (*p == '-')
|
|
361
|
-
{
|
|
362
|
-
frac = true;
|
|
363
|
-
++p;
|
|
364
|
-
}
|
|
365
|
-
else if (*p == '+')
|
|
366
|
-
++p;
|
|
367
|
-
|
|
368
|
-
// Get digits of exponent, if any.
|
|
369
|
-
while (IS_DIGIT(*p))
|
|
370
|
-
{
|
|
371
|
-
expon = expon * 10 + (*p - '0');
|
|
372
|
-
++p;
|
|
373
|
-
}
|
|
374
|
-
if (expon > 308)
|
|
375
|
-
expon = 308;
|
|
244
|
+
static double fast_strtod( const char * buffer, int size, int * processed_chars );
|
|
376
245
|
|
|
377
|
-
|
|
378
|
-
while (expon >= 50)
|
|
379
|
-
{
|
|
380
|
-
scale *= 1E50;
|
|
381
|
-
expon -= 50;
|
|
382
|
-
}
|
|
383
|
-
while (expon >= 8)
|
|
384
|
-
{
|
|
385
|
-
scale *= 1E8;
|
|
386
|
-
expon -= 8;
|
|
387
|
-
}
|
|
388
|
-
while (expon > 0)
|
|
389
|
-
{
|
|
390
|
-
scale *= 10.0;
|
|
391
|
-
expon -= 1;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
246
|
+
static int fast_dtoa( char * buffer, int size, double value );
|
|
394
247
|
|
|
395
|
-
|
|
396
|
-
return sign * (frac ? (value / scale) : (value * scale));
|
|
397
|
-
}
|
|
248
|
+
static int fast_fixed_dtoa( char * buffer, int size, double value );
|
|
398
249
|
|
|
399
250
|
public:
|
|
400
251
|
|
|
252
|
+
static const int SIGNIFICANT_DIGITS = 15;
|
|
253
|
+
static const int BUFFFER_SIZE = 32;
|
|
254
|
+
|
|
401
255
|
static std::string convert( double value, int padding = 0 )
|
|
402
256
|
{
|
|
403
|
-
char result[
|
|
257
|
+
char result[BUFFFER_SIZE];
|
|
404
258
|
char *end = 0;
|
|
405
259
|
|
|
406
260
|
int size;
|
|
407
|
-
if( value == 0 || value > 0.0001 || value
|
|
261
|
+
if( value == 0 || value > 0.0001 || value < -0.0001 )
|
|
408
262
|
{
|
|
409
|
-
size =
|
|
263
|
+
size = fast_dtoa( result, BUFFFER_SIZE, value );
|
|
264
|
+
if( size == 0 )
|
|
265
|
+
return std::string();
|
|
410
266
|
|
|
411
267
|
if( padding > 0 )
|
|
412
268
|
{
|
|
@@ -419,42 +275,44 @@ public:
|
|
|
419
275
|
{
|
|
420
276
|
end = point;
|
|
421
277
|
*point = '.';
|
|
422
|
-
size
|
|
278
|
+
++size;
|
|
423
279
|
}
|
|
424
280
|
int needed = padding - (int)(end - point);
|
|
425
281
|
|
|
426
|
-
|
|
282
|
+
if( needed > 0 )
|
|
427
283
|
{
|
|
428
|
-
|
|
429
|
-
size
|
|
284
|
+
memset( ++end, '0', needed );
|
|
285
|
+
size += needed;
|
|
430
286
|
}
|
|
431
|
-
*(end+1) = 0;
|
|
432
287
|
}
|
|
433
288
|
}
|
|
434
289
|
else
|
|
435
290
|
{
|
|
436
|
-
size =
|
|
291
|
+
size = fast_fixed_dtoa( result, BUFFFER_SIZE, value );
|
|
292
|
+
if( size == 0 )
|
|
293
|
+
return std::string();
|
|
294
|
+
|
|
437
295
|
// strip trailing 0's
|
|
438
296
|
end = result + size - 1;
|
|
439
297
|
|
|
440
298
|
if( padding > 0 )
|
|
441
299
|
{
|
|
442
|
-
int discard =
|
|
300
|
+
int discard = SIGNIFICANT_DIGITS - padding;
|
|
443
301
|
|
|
444
302
|
while( (*end == '0') && (discard-- > 0) )
|
|
445
303
|
{
|
|
446
|
-
|
|
447
|
-
size
|
|
304
|
+
--end;
|
|
305
|
+
--size;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else
|
|
309
|
+
{
|
|
310
|
+
while( *end == '0' )
|
|
311
|
+
{
|
|
312
|
+
--end;
|
|
313
|
+
--size;
|
|
448
314
|
}
|
|
449
|
-
|
|
450
|
-
else
|
|
451
|
-
{
|
|
452
|
-
while( *end == '0' )
|
|
453
|
-
{
|
|
454
|
-
*(end--) = 0;
|
|
455
|
-
size--;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
315
|
+
}
|
|
458
316
|
}
|
|
459
317
|
|
|
460
318
|
return std::string( result, size );
|
|
@@ -485,10 +343,20 @@ static bool convert( const std::string& value, double& result )
|
|
|
485
343
|
|
|
486
344
|
if( *i || !haveDigit ) return false;
|
|
487
345
|
|
|
488
|
-
|
|
489
|
-
|
|
346
|
+
int processed_chars;
|
|
347
|
+
const int total_length = value.length();
|
|
348
|
+
const double val = fast_strtod( value.c_str(), total_length, &processed_chars);
|
|
349
|
+
|
|
350
|
+
if ( processed_chars != total_length ||
|
|
351
|
+
val != val /*test for quite NaN*/ )
|
|
352
|
+
{
|
|
353
|
+
return false;
|
|
490
354
|
}
|
|
491
355
|
|
|
356
|
+
result = val;
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
492
360
|
static double convert( const std::string& value )
|
|
493
361
|
throw( FieldConvertError )
|
|
494
362
|
{
|
|
@@ -564,52 +432,45 @@ struct BoolConvertor
|
|
|
564
432
|
struct UtcTimeStampConvertor
|
|
565
433
|
{
|
|
566
434
|
static std::string convert( const UtcTimeStamp& value,
|
|
567
|
-
|
|
435
|
+
int precision = 0 )
|
|
568
436
|
throw( FieldConvertError )
|
|
569
437
|
{
|
|
570
|
-
char result[
|
|
571
|
-
int year, month, day, hour, minute, second,
|
|
438
|
+
char result[ 17+10 ]; // Maximum
|
|
439
|
+
int year, month, day, hour, minute, second, fraction;
|
|
572
440
|
|
|
573
441
|
value.getYMD( year, month, day );
|
|
574
|
-
value.getHMS( hour, minute, second,
|
|
442
|
+
value.getHMS( hour, minute, second, fraction, precision );
|
|
575
443
|
|
|
576
|
-
integer_to_string_padded( result,
|
|
577
|
-
integer_to_string_padded( result + 4,
|
|
578
|
-
integer_to_string_padded( result + 6,
|
|
444
|
+
integer_to_string_padded( result, 4, year);
|
|
445
|
+
integer_to_string_padded( result + 4, 2, month );
|
|
446
|
+
integer_to_string_padded( result + 6, 2, day );
|
|
579
447
|
result[8] = '-';
|
|
580
|
-
integer_to_string_padded( result + 9,
|
|
448
|
+
integer_to_string_padded( result + 9, 2, hour);
|
|
581
449
|
result[11] = ':';
|
|
582
|
-
integer_to_string_padded( result + 12,
|
|
450
|
+
integer_to_string_padded( result + 12, 2, minute);
|
|
583
451
|
result[14] = ':';
|
|
584
|
-
integer_to_string_padded( result + 15,
|
|
452
|
+
integer_to_string_padded( result + 15, 2, second);
|
|
585
453
|
|
|
586
|
-
if(
|
|
454
|
+
if( precision )
|
|
587
455
|
{
|
|
588
456
|
result[17] = '.';
|
|
589
|
-
if( integer_to_string_padded ( result + 18,
|
|
457
|
+
if( integer_to_string_padded ( result + 18, precision, fraction )
|
|
590
458
|
!= result + 18 )
|
|
591
459
|
{
|
|
592
460
|
throw FieldConvertError();
|
|
593
461
|
}
|
|
594
462
|
}
|
|
595
463
|
|
|
596
|
-
return result;
|
|
464
|
+
return std::string(result, precision ? (17 + 1 + precision) : 17);
|
|
597
465
|
}
|
|
598
466
|
|
|
599
|
-
static UtcTimeStamp convert( const std::string& value
|
|
600
|
-
bool calculateDays = false )
|
|
467
|
+
static UtcTimeStamp convert( const std::string& value )
|
|
601
468
|
throw( FieldConvertError )
|
|
602
469
|
{
|
|
603
|
-
|
|
470
|
+
size_t len = value.size();
|
|
471
|
+
if (len < 17 || len > 27) throw FieldConvertError(value);
|
|
604
472
|
|
|
605
|
-
|
|
606
|
-
{
|
|
607
|
-
case 21: haveMilliseconds = true;
|
|
608
|
-
case 17: break;
|
|
609
|
-
default: throw FieldConvertError(value);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
int i = 0;
|
|
473
|
+
size_t i = 0;
|
|
613
474
|
int c = 0;
|
|
614
475
|
for( c = 0; c < 8; ++c )
|
|
615
476
|
if( !IS_DIGIT(value[i++]) ) throw FieldConvertError(value);
|
|
@@ -623,14 +484,7 @@ struct UtcTimeStampConvertor
|
|
|
623
484
|
for( c = 0; c < 2; ++c )
|
|
624
485
|
if( !IS_DIGIT(value[i++]) ) throw FieldConvertError(value);
|
|
625
486
|
|
|
626
|
-
|
|
627
|
-
{
|
|
628
|
-
if( value[i++] != '.' ) throw FieldConvertError(value);
|
|
629
|
-
for( c = 0; c < 3; ++c )
|
|
630
|
-
if( !IS_DIGIT(value[i++]) ) throw FieldConvertError(value);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
int year, mon, mday, hour, min, sec, millis;
|
|
487
|
+
int year, mon, mday, hour, min, sec;
|
|
634
488
|
|
|
635
489
|
i = 0;
|
|
636
490
|
|
|
@@ -669,17 +523,22 @@ struct UtcTimeStampConvertor
|
|
|
669
523
|
// No check for >= 0 as no '-' are converted here
|
|
670
524
|
if( 60 < sec ) throw FieldConvertError(value);
|
|
671
525
|
|
|
672
|
-
if(
|
|
526
|
+
if (len == 17)
|
|
527
|
+
return UtcTimeStamp (hour, min, sec, 0,
|
|
528
|
+
mday, mon, year);
|
|
529
|
+
|
|
530
|
+
if( value[i++] != '.' ) throw FieldConvertError(value);
|
|
531
|
+
|
|
532
|
+
int fraction = 0;
|
|
533
|
+
for (; i < len; ++i)
|
|
673
534
|
{
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
535
|
+
char ch = value[i];
|
|
536
|
+
if( !IS_DIGIT(ch)) throw FieldConvertError(value);
|
|
537
|
+
fraction = (fraction * 10) + ch - '0';
|
|
677
538
|
}
|
|
678
|
-
else
|
|
679
|
-
millis = 0;
|
|
680
539
|
|
|
681
|
-
return UtcTimeStamp (hour, min, sec,
|
|
682
|
-
mday, mon, year);
|
|
540
|
+
return UtcTimeStamp (hour, min, sec, fraction,
|
|
541
|
+
mday, mon, year, len - 17 - 1);
|
|
683
542
|
}
|
|
684
543
|
};
|
|
685
544
|
|
|
@@ -687,44 +546,38 @@ struct UtcTimeStampConvertor
|
|
|
687
546
|
struct UtcTimeOnlyConvertor
|
|
688
547
|
{
|
|
689
548
|
static std::string convert( const UtcTimeOnly& value,
|
|
690
|
-
|
|
549
|
+
int precision = 0 )
|
|
691
550
|
throw( FieldConvertError )
|
|
692
551
|
{
|
|
693
|
-
char result[
|
|
694
|
-
int hour, minute, second,
|
|
552
|
+
char result[ 8+10 ]; // Maximum
|
|
553
|
+
int hour, minute, second, fraction;
|
|
695
554
|
|
|
696
|
-
value.getHMS( hour, minute, second,
|
|
555
|
+
value.getHMS( hour, minute, second, fraction, precision );
|
|
697
556
|
|
|
698
|
-
integer_to_string_padded ( result,
|
|
557
|
+
integer_to_string_padded ( result, 2, hour );
|
|
699
558
|
result[2] = ':';
|
|
700
|
-
integer_to_string_padded ( result + 3,
|
|
559
|
+
integer_to_string_padded ( result + 3, 2, minute );
|
|
701
560
|
result[5] = ':';
|
|
702
|
-
integer_to_string_padded ( result + 6,
|
|
561
|
+
integer_to_string_padded ( result + 6, 2, second );
|
|
703
562
|
|
|
704
|
-
if(
|
|
563
|
+
if( precision )
|
|
705
564
|
{
|
|
706
565
|
result[8] = '.';
|
|
707
|
-
if( integer_to_string_padded ( result + 9,
|
|
566
|
+
if( integer_to_string_padded ( result + 9, precision, fraction )
|
|
708
567
|
!= result + 9 )
|
|
709
568
|
throw FieldConvertError();
|
|
710
569
|
}
|
|
711
570
|
|
|
712
|
-
return result;
|
|
571
|
+
return std::string(result, precision ? (8 + 1 + precision) : 8);
|
|
713
572
|
}
|
|
714
573
|
|
|
715
|
-
static UtcTimeOnly convert( const std::string& value
|
|
574
|
+
static UtcTimeOnly convert( const std::string& value)
|
|
716
575
|
throw( FieldConvertError )
|
|
717
576
|
{
|
|
718
|
-
|
|
577
|
+
size_t len = value.size();
|
|
578
|
+
if (len < 8 || len > 18) throw FieldConvertError(value);
|
|
719
579
|
|
|
720
|
-
|
|
721
|
-
{
|
|
722
|
-
case 12: haveMilliseconds = true;
|
|
723
|
-
case 8: break;
|
|
724
|
-
default: throw FieldConvertError(value);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
int i = 0;
|
|
580
|
+
size_t i = 0;
|
|
728
581
|
int c = 0;
|
|
729
582
|
for( c = 0; c < 2; ++c )
|
|
730
583
|
if( !IS_DIGIT(value[i++]) ) throw FieldConvertError(value);
|
|
@@ -735,44 +588,44 @@ struct UtcTimeOnlyConvertor
|
|
|
735
588
|
for( c = 0; c < 2; ++c )
|
|
736
589
|
if( !IS_DIGIT(value[i++]) ) throw FieldConvertError(value);
|
|
737
590
|
|
|
738
|
-
|
|
739
|
-
{
|
|
740
|
-
// ++i instead of i++ skips the '.' separator
|
|
741
|
-
for( c = 0; c < 3; ++c )
|
|
742
|
-
if( !IS_DIGIT(value[++i]) ) throw FieldConvertError(value);
|
|
743
|
-
}
|
|
591
|
+
int hour, min, sec;
|
|
744
592
|
|
|
745
|
-
int hour, min, sec, millis;
|
|
746
|
-
|
|
747
593
|
i = 0;
|
|
748
594
|
|
|
749
595
|
hour = value[i++] - '0';
|
|
750
596
|
hour = 10 * hour + value[i++] - '0';
|
|
751
597
|
// No check for >= 0 as no '-' are converted here
|
|
752
598
|
if( 23 < hour ) throw FieldConvertError(value);
|
|
599
|
+
|
|
753
600
|
++i; // skip ':'
|
|
754
601
|
|
|
755
602
|
min = value[i++] - '0';
|
|
756
603
|
min = 10 * min + value[i++] - '0';
|
|
757
604
|
// No check for >= 0 as no '-' are converted here
|
|
758
605
|
if( 59 < min ) throw FieldConvertError(value);
|
|
606
|
+
|
|
759
607
|
++i; // skip ':'
|
|
760
608
|
|
|
761
609
|
sec = value[i++] - '0';
|
|
762
610
|
sec = 10 * sec + value[i++] - '0';
|
|
611
|
+
|
|
763
612
|
// No check for >= 0 as no '-' are converted here
|
|
764
613
|
if( 60 < sec ) throw FieldConvertError(value);
|
|
765
614
|
|
|
766
|
-
if(
|
|
615
|
+
if (len == 8)
|
|
616
|
+
return UtcTimeOnly (hour, min, sec, 0);
|
|
617
|
+
|
|
618
|
+
if( value[i++] != '.' ) throw FieldConvertError(value);
|
|
619
|
+
|
|
620
|
+
int fraction = 0;
|
|
621
|
+
for (; i < len; ++i)
|
|
767
622
|
{
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
623
|
+
char ch = value[i];
|
|
624
|
+
if( !IS_DIGIT(ch)) throw FieldConvertError(value);
|
|
625
|
+
fraction = (fraction * 10) + ch - '0';
|
|
771
626
|
}
|
|
772
|
-
else
|
|
773
|
-
millis = 0;
|
|
774
627
|
|
|
775
|
-
return UtcTimeOnly(
|
|
628
|
+
return UtcTimeOnly (hour, min, sec, fraction, len - 8 - 1);
|
|
776
629
|
}
|
|
777
630
|
};
|
|
778
631
|
|
|
@@ -782,15 +635,16 @@ struct UtcDateConvertor
|
|
|
782
635
|
static std::string convert( const UtcDate& value )
|
|
783
636
|
throw( FieldConvertError )
|
|
784
637
|
{
|
|
785
|
-
char result[ 9 ];
|
|
786
638
|
int year, month, day;
|
|
787
|
-
|
|
788
639
|
value.getYMD( year, month, day );
|
|
789
640
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
integer_to_string_padded( result
|
|
793
|
-
|
|
641
|
+
char result[ 8 ];
|
|
642
|
+
|
|
643
|
+
integer_to_string_padded( result, 4, year );
|
|
644
|
+
integer_to_string_padded( result + 4, 2, month );
|
|
645
|
+
integer_to_string_padded( result + 6, 2, day );
|
|
646
|
+
|
|
647
|
+
return std::string( result, sizeof( result ) );
|
|
794
648
|
}
|
|
795
649
|
|
|
796
650
|
static UtcDate convert( const std::string& value )
|