fix8  version 1.4.0
Open Source C++ FIX Framework
message.cpp
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------------------
2 /*
3 
4 Fix8 is released under the GNU LESSER GENERAL PUBLIC LICENSE Version 3.
5 
6 Fix8 Open Source FIX Engine.
7 Copyright (C) 2010-16 David L. Dight <fix@fix8.org>
8 
9 Fix8 is free software: you can redistribute it and / or modify it under the terms of the
10 GNU Lesser General Public License as published by the Free Software Foundation, either
11 version 3 of the License, or (at your option) any later version.
12 
13 Fix8 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 You should have received a copy of the GNU Lesser General Public License along with Fix8.
17 If not, see <http://www.gnu.org/licenses/>.
18 
19 BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO
20 THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
21 COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
22 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
24 THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
25 YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
26 
27 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT
28 HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED
29 ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
30 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
31 NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
32 THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
33 HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 
35 */
36 //-----------------------------------------------------------------------------------------
37 #include "precomp.hpp"
38 #include <fix8/f8includes.hpp>
39 
40 //-------------------------------------------------------------------------------------------------
41 using namespace FIX8;
42 using namespace std;
43 
44 //-------------------------------------------------------------------------------------------------
45 #if defined FIX8_CODECTIMING
46 codec_timings Message::_encode_timings, Message::_decode_timings;
47 #endif
49 
50 //-------------------------------------------------------------------------------------------------
51 unsigned MessageBase::extract_header(const f8String& from, char *len, char *mtype)
52 {
53  const char *dptr(from.data());
54  const unsigned flen(static_cast<unsigned>(from.size()));
56  unsigned s_offset(0), result;
57 
58  if ((result = extract_element(dptr, flen, tag, val)))
59  {
60  if (*tag != '8')
61  return 0;
62  s_offset += result;
63  if ((result = extract_element(dptr + s_offset, flen - s_offset, tag, len)))
64  {
65  if (*tag != '9')
66  return 0;
67  s_offset += result;
68  if ((result = extract_element(dptr + s_offset, flen - s_offset, tag, mtype)))
69  {
70  if (*tag != '3' || *(tag + 1) != '5')
71  return 0;
72  s_offset += result;
73  }
74  }
75  }
76  return s_offset;
77 }
78 
79 //-------------------------------------------------------------------------------------------------
80 unsigned MessageBase::extract_trailer(const f8String& from, f8String& chksum)
81 {
82  f8String tag;
83  return extract_element(from.data() + from.size() - 7, 6, tag, chksum);
84 }
85 
86 //-------------------------------------------------------------------------------------------------
87 unsigned MessageBase::decode(const f8String& from, unsigned s_offset, unsigned ignore, bool permissive_mode)
88 {
89  const unsigned fsize(static_cast<unsigned>(from.size()) - ignore), npos(0xffffffff);
90  unsigned pos(static_cast<unsigned>(_pos.size())), last_valid_pos(npos);
91  const char *dptr(from.data());
93  size_t last_valid_offset(0);
94 
95  for (unsigned result; s_offset <= fsize && (result = extract_element(dptr + s_offset, fsize - s_offset, tag, val));)
96  {
97  unsigned short tv(fast_atoi<unsigned short>(tag));
98  Presence::const_iterator itr(_fp.get_presence().find(tv));
99  if (itr == _fp.get_presence().end())
100  {
101 unknown_field:
102  if (permissive_mode)
103  {
104  if (last_valid_pos == npos)
105  {
106  last_valid_pos = pos;
107  last_valid_offset = s_offset;
108  }
109  _unknown.append(dptr + s_offset, result);
110  s_offset += result;
111  continue;
112  }
113  break;
114  }
115  s_offset += result;
116  if (itr->_field_traits.has(FieldTrait::present))
117  {
118  if (!itr->_field_traits.has(FieldTrait::automatic))
119  throw DuplicateField(tv);
120  }
121  else for(unsigned ii(0); ii < 2; ++ii)
122  {
123  const BaseEntry *be(_ctx.find_be(tv));
124  if (!be)
125  throw UnknownField(tv);
126  BaseField *bf(be->_create._do(val, be->_rlm, -1));
127  add_field_decoder(tv, ++pos, bf);
128  itr->_field_traits.set(FieldTrait::present);
129  // check if repeating group and num elements > 0
130  if (itr->_field_traits.has(FieldTrait::group) && has_group_count(bf))
131  s_offset = decode_group(nullptr, tv, from, s_offset, ignore);
132 
133  if (itr->_ftype != FieldTrait::ft_Length || tv == Common_BodyLength) // this type expects next field to be data
134  break;
135 
136  const unsigned val_sz(fast_atoi<unsigned>(val));
137  if(val_sz > FIX8_MAX_FLD_LENGTH - 1)
138  throw f8Exception("Value size too large");
139  result = extract_element_fixed_width(dptr + s_offset, fsize - s_offset, val_sz, tag, val);
140  if (!result)
141  throw MissingMandatoryField("Unable to extract fixed width field");
142 
143  const unsigned short lasttv(tv);
144  tv = fast_atoi<unsigned short>(tag);
145  if ((itr = _fp.get_presence().find(tv)) == _fp.get_presence().end())
146  goto unknown_field;
147  if (itr->_ftype != FieldTrait::ft_data || lasttv + 1 != tv) // next field must be data, tag must be 1 greater than length tag
148  break;
149  s_offset += result;
150  }
151  }
152 
153  const unsigned short missing(_fp.find_missing());
154  if (missing)
155  {
156  const BaseEntry *tbe(_ctx.find_be(missing));
157  ostringstream ostr;
158  ostr << tbe->_name << " (" << missing << ')';
159  throw MissingMandatoryField(ostr.str());
160  }
161 
162  return permissive_mode && last_valid_pos == pos ? static_cast<unsigned>(last_valid_offset) : s_offset;
163 }
164 
165 //-------------------------------------------------------------------------------------------------
166 unsigned MessageBase::decode_group(GroupBase *grpbase, const unsigned short fnum, const f8String& from,
167  unsigned s_offset, unsigned ignore)
168 {
169  unsigned result;
170  if (!(grpbase = find_add_group(fnum, grpbase)))
171  throw InvalidRepeatingGroup(fnum, FILE_LINE);
172  const unsigned fsize(static_cast<unsigned>(from.size()) - ignore);
173  const char *dptr(from.data());
175 
176  for (bool ok(true); ok && s_offset < fsize; )
177  {
178  unique_ptr<MessageBase> grp(grpbase->create_group(false)); // shallow create
179 
180  for (unsigned pos(0); s_offset < fsize && (result = extract_element(dptr + s_offset, fsize - s_offset, tag, val));)
181  {
182  const unsigned tv(fast_atoi<unsigned>(tag));
183  Presence::const_iterator itr(grp->_fp.get_presence().end());
184  if (grp->_fp.get(tv, itr, FieldTrait::present)) // already present; next group?
185  break;
186  if (pos == 0 && grp->_fp.getPos(tv, itr) != 1) // first field in group is mandatory
187  throw MissingRepeatingGroupField(tv);
188  const BaseEntry *be(_ctx.find_be(tv));
189  if (!be || !grp->_fp.has(tv, itr)) // unknown field or field not found in sub-group - end of repeats?
190  {
191  ok = false;
192  break;
193  }
194  s_offset += result;
195  BaseField *bf(be->_create._do(val, be->_rlm, -1));
196  grp->add_field(tv, itr, ++pos, bf, false);
197  grp->_fp.set(tv, itr, FieldTrait::present); // is present
198  // nested group (check if not zero elements)
199  if (grp->_fp.is_group(tv, itr) && has_group_count(bf))
200  s_offset = grp->decode_group(grpbase, tv, from, s_offset, ignore);
201  }
202 
203  const unsigned short missing(grp->_fp.find_missing());
204  if (missing)
205  {
206  const BaseEntry *tbe(_ctx.find_be(missing));
207  ostringstream ostr;
208  ostr << tbe->_name << " (" << missing << ')';
209  throw MissingMandatoryField(ostr.str());
210  }
211  *grpbase << grp.release();
212  }
213 
214  return s_offset;
215 }
216 
217 //-------------------------------------------------------------------------------------------------
219 {
220  return 0; // TODO
221 }
222 
223 //-------------------------------------------------------------------------------------------------
224 Message *Message::factory(const F8MetaCntx& ctx, const f8String& from, bool no_chksum, bool permissive_mode)
225 {
226  char mtype[MAX_MSGTYPE_FIELD_LEN] {}, len[MAX_MSGTYPE_FIELD_LEN] {};
227  const unsigned hlen(extract_header(from, len, mtype));
228 
229  if (!hlen)
230  {
231  glout_debug << "Message::factory throwing";
232  throw InvalidMessage(from, FILE_LINE);
233  }
234 
235  const unsigned mlen(fast_atoi<unsigned>(len));
236  const BaseMsgEntry *bme(ctx._bme.find_ptr(mtype));
237  if (!bme)
238  throw InvalidMessage(mtype, FILE_LINE);
239  Message *msg(bme->_create._do(false)); // shallow create
240 #if defined FIX8_CODECTIMING
241  IntervalTimer itm;
242 #endif
243  msg->decode(from, hlen, 7, permissive_mode); // skip already decoded mandatory 8, 9, 35 and 10
244 #if defined FIX8_CODECTIMING
245  _decode_timings._cpu_used += itm.Calculate().AsDouble();
246  ++_decode_timings._msg_count;
247 #endif
248 
249  msg->_header->get_body_length()->set(mlen);
250  msg->_header->get_msg_type()->set(mtype);
251 #if defined FIX8_POPULATE_METADATA
252  msg->check_set_rlm(fitr->second);
253 #endif
254 
255  const char *pp(from.data() + from.size() - 7); // FIXME: assumes supplied string is one complete message only
256  if (*pp != '1' || *(pp + 1) != '0') // 10=XXX^A
257  throw InvalidMessage(from, FILE_LINE);
258  if (!no_chksum) // permit chksum calculation to be skipped
259  {
260  const f8String chksum(pp + 3, 3);
261  msg->_trailer->get_check_sum()->set(chksum);
262  const unsigned chkval(fast_atoi<unsigned>(chksum.c_str())), mchkval(calc_chksum(from, 0, static_cast<unsigned>(from.size()) - 7));
263  if (chkval != mchkval)
264  throw BadCheckSum(mchkval);
265  }
266 
267  return msg;
268 }
269 
270 //-------------------------------------------------------------------------------------------------
271 // copy all fields from this message to 'to' where the field is legal for 'to' and it is not
272 // already present in 'to'; includes repeating groups;
273 // a deep constructed target message is required
274 // if force, copy all fields regardless, replacing any existing, adding any new
275 unsigned MessageBase::copy_legal(MessageBase *to, bool force) const
276 {
277  unsigned copied{};
278  for (const auto& pp : _fp.get_presence())
279  {
280  if (pp._field_traits & FieldTrait::present && (force || (to->_fp.has(pp._fnum) && !to->_fp.get(pp._fnum))))
281  {
282  GroupBase *gb;
283  if (pp._field_traits & FieldTrait::group && (gb = find_group(pp._fnum)))
284  {
285  GroupBase *gb1(to->find_group(pp._fnum));
286  for (const auto *qq : gb->_msgs)
287  {
288  MessageBase *grc(gb1->create_group(true));
289  copied += qq->copy_legal(grc, force);
290  *gb1 += grc;
291  }
292  }
293 
294  BaseField *nf(get_field(pp._fnum)->copy());
295 #if defined FIX8_POPULATE_METADATA
296  to->check_set_rlm(nf);
297 #endif
299  if (force && to->_fp.get(pp._fnum, fpitr, FieldTrait::present))
300  delete to->replace(pp._fnum, fpitr, nf);
301  else
302  to->add_field(nf);
303  ++copied;
304  }
305  }
306 
307  return copied;
308 }
309 
310 //-------------------------------------------------------------------------------------------------
311 // move all fields from this message to 'to' where the field is legal for 'to' and it is not
312 // already present in 'to'; includes repeating groups;
313 // if force, move all fields regardless, replacing any existing
314 // not thread safe
315 unsigned MessageBase::move_legal(MessageBase *to, bool force)
316 {
317  unsigned moved{};
318  for (const auto& pp : _fp.get_presence())
319  {
320  if (pp._field_traits & FieldTrait::present && (force || (to->_fp.has(pp._fnum) && !to->_fp.get(pp._fnum))))
321  {
322  if (pp._field_traits & FieldTrait::group)
323  {
324  auto gitr(_groups.find(pp._fnum));
325  GroupBase *gb1(to->find_group(pp._fnum));
326  if (gb1)
327  delete to->replace(pp._fnum, gitr->second);
328  else
329  *to += gitr->second;
330  gitr->second = nullptr;
331  }
332 
333  auto itr(_fields.find(pp._fnum));
334  Presence::const_iterator fpitr(_fp.get_presence().end());
335  if (force && to->_fp.get(pp._fnum, fpitr, FieldTrait::present))
336  delete to->replace(pp._fnum, fpitr, itr->second);
337  else
338  to->add_field(itr->second);
339  itr->second = nullptr;
340  ++moved;
341  }
342  }
343  clear_positions();
344 
345  return moved;
346 }
347 
348 //-------------------------------------------------------------------------------------------------
349 size_t MessageBase::encode(char *to) const
350 {
351  const char *where(to);
352  for (const auto& pp : _pos)
353  {
354 #if defined FIX8_POPULATE_METADATA
355  check_set_rlm(pp.second);
356 #endif
357  Presence::const_iterator fpitr(_fp.get_presence().end());
358  if (!_fp.get(pp.second->_fnum, fpitr, FieldTrait::suppress)) // some fields are not encoded until unsuppressed (eg. checksum)
359  {
360  to += pp.second->encode(to);
361  if (fpitr->_field_traits.has(FieldTrait::group) && has_group_count(pp.second))
362  to += encode_group(pp.second->_fnum, to);
363  }
364  }
365 
366  if (_unknown.size())
367  to += _unknown.copy(to, _unknown.size());
368 
369  return to - where;
370 }
371 
372 //-------------------------------------------------------------------------------------------------
373 size_t MessageBase::encode(ostream& to) const
374 {
375  const std::ios::pos_type where(to.tellp());
376  for (const auto& pp : _pos)
377  {
378 #if defined FIX8_POPULATE_METADATA
379  check_set_rlm(pp.second);
380 #endif
381  Presence::const_iterator fpitr(_fp.get_presence().end());
382  if (!_fp.get(pp.second->_fnum, fpitr, FieldTrait::suppress)) // some fields are not encoded until unsuppressed (eg. checksum)
383  {
384  pp.second->encode(to);
385  if (fpitr->_field_traits.has(FieldTrait::group) && has_group_count(pp.second))
386  encode_group(pp.second->_fnum, to);
387  }
388  }
389 
390  if (_unknown.size())
391  to << _unknown;
392 
393  return to.tellp() - where;
394 }
395 
396 //-------------------------------------------------------------------------------------------------
397 size_t MessageBase::encode_group(const unsigned short fnum, char *to) const
398 {
399  const char *where(to);
400  GroupBase *grpbase(find_group(fnum));
401  if (!grpbase)
402  throw InvalidRepeatingGroup(fnum, FILE_LINE);
403  for (const auto *pp : grpbase->_msgs)
404  to += pp->encode(to);
405  return to - where;
406 }
407 
408 //-------------------------------------------------------------------------------------------------
409 size_t MessageBase::encode_group(const unsigned short fnum, std::ostream& to) const
410 {
411  const std::ios::pos_type where(to.tellp());
412  GroupBase *grpbase(find_group(fnum));
413  if (!grpbase)
414  throw InvalidRepeatingGroup(fnum, FILE_LINE);
415  for (const auto *pp : grpbase->_msgs)
416  pp->encode(to);
417  return to.tellp() - where;
418 }
419 
420 //-------------------------------------------------------------------------------------------------
422 size_t Message::encode(char **hmsg_store) const
423 {
424  char *moffs(*hmsg_store + HEADER_CALC_OFFSET), *msg(moffs);
425 
426 #if defined FIX8_CODECTIMING
427  IntervalTimer itm;
428 #endif
429 
430  if (!_header)
431  throw MissingMessageComponent("header");
432  _header->get_msg_type()->set(_msgType);
433 
434 #if defined FIX8_RAW_MSG_SUPPORT
435  msg += (_begin_payload = _header->encode(msg)); // start
436 #if defined FIX8_PREENCODE_MSG_SUPPORT
437  if (_preencode_len)
438  {
439  ::memcpy(msg, _preencode.data(), _payload_len =_preencode_len);
440  msg += _preencode_len;
441  }
442  else
443 #endif
444  msg += (_payload_len = MessageBase::encode(msg));
445 #else
446  msg += _header->encode(msg); // start
447 #if defined FIX8_PREENCODE_MSG_SUPPORT
448  if (_preencode_len)
449  {
450  ::memcpy(msg, _preencode.data(), _preencode_len);
451  msg += _preencode_len;
452  }
453  else
454 #endif
455  msg += MessageBase::encode(msg);
456 #endif
457 
458  if (!_trailer)
459  throw MissingMessageComponent("trailer");
460  msg += _trailer->encode(msg);
461  const size_t msgLen(msg - moffs); // checksummable msglength
462  const size_t hlen(_ctx._preamble_sz +
463  (msgLen < 10 ? 1 : msgLen < 100 ? 2 : msgLen < 1000 ? 3 : msgLen < 10000 ? 4 :
464  msgLen < 100000 ? 5 : msgLen < 1000000 ? 6 : 7));
465  char *hmsg(moffs - hlen);
466  *hmsg_store = hmsg;
467 
468  if (!_header->get_begin_string())
470  _header->_fp.clear(Common_BeginString, FieldTrait::suppress);
471  hmsg += _header->get_begin_string()->encode(hmsg);
472 
473  if (!_header->get_body_length())
475  _header->_fp.clear(Common_BodyLength, FieldTrait::suppress);
476 
477  _header->get_body_length()->set(static_cast<int>(msgLen));
478  hmsg += _header->get_body_length()->encode(hmsg);
479 
480  if (!_trailer->get_check_sum())
482  _trailer->get_check_sum()->set(fmt_chksum(calc_chksum(moffs - hlen, msgLen + hlen)));
483  _trailer->_fp.clear(Common_CheckSum, FieldTrait::suppress);
484  msg += _trailer->get_check_sum()->encode(msg);
485 
486 #if defined FIX8_CODECTIMING
487  _encode_timings._cpu_used += itm.Calculate().AsDouble();
488  ++_encode_timings._msg_count;
489 #endif
490 
491  *msg = 0;
492  const size_t rlen(msg - *hmsg_store);
493 #if defined FIX8_RAW_MSG_SUPPORT
494  _rawmsg.assign(*hmsg_store, rlen);
495 #endif
496  return rlen;
497 }
498 
499 //-------------------------------------------------------------------------------------------------
500 size_t Message::encode(f8String& to) const
501 {
502  char output[FIX8_MAX_MSG_LENGTH + HEADER_CALC_OFFSET], *ptr(output);
503  const size_t msgLen(encode(&ptr));
504  to.assign(ptr, msgLen);
505  return to.size();
506 }
507 
508 //-------------------------------------------------------------------------------------------------
509 void MessageBase::print(ostream& os, int depth) const
510 {
511  const string dspacer((depth + 1) * _tabsize, ' ');
512  const BaseMsgEntry *tbme(_ctx._bme.find_ptr(_msgType.c_str()));
513  if (tbme)
514  os << string(depth * _tabsize, ' ') << tbme->_name << " (\"" << _msgType << "\")" << endl;
515  for (const auto& pp : _pos)
516  {
517  const BaseEntry *tbe(_ctx.find_be(pp.second->_fnum));
518  if (!tbe)
519  throw InvalidField(pp.second->_fnum);
520  os << dspacer << tbe->_name;
521  const unsigned short comp(_fp.getComp(pp.second->_fnum));
522  if (comp)
523  os << " [" << _ctx._cn[comp] << ']';
524  os << " (" << pp.second->_fnum << "): ";
525  int idx;
526  if (pp.second->_rlm && (idx = (pp.second->get_rlm_idx())) >= 0)
527  os << pp.second->_rlm->_descriptions[idx] << " (" << *pp.second << ')' << endl;
528  else
529  os << *pp.second << endl;
530  if (_fp.is_group(pp.second->_fnum) && has_group_count(pp.second))
531  print_group(pp.second->_fnum, os, depth);
532  }
533 }
534 
535 //-------------------------------------------------------------------------------------------------
536 void MessageBase::print_group(const unsigned short fnum, ostream& os, int depth) const
537 {
538  const GroupBase *grpbase(find_group(fnum));
539  if (!grpbase)
540  throw InvalidRepeatingGroup(fnum, FILE_LINE);
541 
542  ++depth;
543  const string dspacer(depth * _tabsize, ' ');
544  size_t cnt(1);
545  for (const auto *pp : grpbase->_msgs)
546  {
547  os << dspacer << pp->_msgType << " (Repeating group " << cnt << '/' << grpbase->_msgs.size() << ')' << endl;
548  pp->print(os, depth);
549  ++cnt;
550  }
551 }
552 
553 //-------------------------------------------------------------------------------------------------
554 void MessageBase::print_field(const unsigned short fnum, ostream& os) const
555 {
556  Fields::const_iterator fitr(_fields.find(fnum));
557  if (fitr != _fields.end())
558  {
559  const BaseEntry *tbe(_ctx.find_be(fnum));
560  if (!tbe)
561  throw InvalidField(fnum);
562  os << tbe->_name << " (" << fnum << "): ";
563  int idx;
564  if (fitr->second->_rlm && (idx = (fitr->second->get_rlm_idx())) >= 0)
565  os << fitr->second->_rlm->_descriptions[idx] << " (" << *fitr->second << ')';
566  else
567  os << *fitr->second;
568  if (_fp.is_group(fnum) && has_group_count(fitr->second))
569  print_group(fnum, os, 0);
570  }
571 }
572 
573 //-------------------------------------------------------------------------------------------------
574 BaseField *MessageBase::replace(const unsigned short fnum, BaseField *with)
575 {
576  BaseField *old(nullptr);
577  Fields::iterator itr(_fields.find(fnum));
578  if (itr != _fields.end())
579  {
580  old = itr->second;
581  unsigned pos(_fp.getPos(fnum));
582  for (Positions::iterator pitr(_pos.begin()); pitr != _pos.end(); ++pitr)
583  {
584  if (pitr->second == old)
585  {
586  pos = pitr->first;
587  _pos.erase(pitr);
588  break;
589  }
590  }
591  _pos.insert({pos, with});
592  itr->second = with;
593  _fp.set(fnum, FieldTrait::present);
594  }
595  return old;
596 }
597 
598 //-------------------------------------------------------------------------------------------------
599 BaseField *MessageBase::replace(const unsigned short fnum, Presence::const_iterator fitr, BaseField *with)
600 {
601  BaseField *old(nullptr);
602  Fields::iterator itr(_fields.find(fnum));
603  if (itr != _fields.end())
604  {
605  old = itr->second;
606  unsigned pos(_fp.getPos(fnum, fitr));
607  for (Positions::iterator pitr(_pos.begin()); pitr != _pos.end(); ++pitr)
608  {
609  if (pitr->second == old)
610  {
611  pos = pitr->first;
612  _pos.erase(pitr);
613  break;
614  }
615  }
616  _pos.insert({pos, with});
617  itr->second = with;
618  _fp.set(fnum, fitr, FieldTrait::present);
619  }
620  return old;
621 }
622 
623 //-------------------------------------------------------------------------------------------------
624 BaseField *MessageBase::remove(const unsigned short fnum)
625 {
626  BaseField *old(nullptr);
627  Fields::iterator itr(_fields.find(fnum));
628  if (itr != _fields.end())
629  {
630  old = itr->second;
631  for (Positions::iterator pitr(_pos.begin()); pitr != _pos.end(); ++pitr)
632  {
633  if (pitr->second == old)
634  {
635  _pos.erase(pitr);
636  break;
637  }
638  }
639  _fp.clear(fnum, FieldTrait::present);
640  _fields.erase(itr);
641  }
642  return old;
643 }
644 
645 //-------------------------------------------------------------------------------------------------
646 BaseField *MessageBase::remove(const unsigned short fnum, Presence::const_iterator fitr)
647 {
648  BaseField *old(nullptr);
649  Fields::iterator itr(_fields.find(fnum));
650  if (itr != _fields.end())
651  {
652  old = itr->second;
653  for (Positions::iterator pitr(_pos.begin()); pitr != _pos.end(); ++pitr)
654  {
655  if (pitr->second == old)
656  {
657  _pos.erase(pitr);
658  break;
659  }
660  }
661  _fp.clear(fnum, fitr, FieldTrait::present);
662  _fields.erase(itr);
663  }
664  return old;
665 }
666 
667 //-------------------------------------------------------------------------------------------------
669 {
670  const BaseMsgEntry& bme(_ctx._bme.find_ref(_msgType.c_str()));
671  Message *msg(bme._create._do(true));
672  // important not to pass force as true with copy_legal here
673  copy_legal(msg);
674  _header->copy_legal(msg->_header);
675  _trailer->copy_legal(msg->_trailer);
676  return msg;
677 }
678 
679 //-------------------------------------------------------------------------------------------------
680 void Message::print(ostream& os, int) const
681 {
682  if (_header)
683  os << *_header;
684  else
685  os << "Null Header" << endl;
686  MessageBase::print(os);
687  if (_trailer)
688  os << *_trailer;
689  else
690  os << "Null Trailer" << endl;
691 }
692 
693 //-------------------------------------------------------------------------------------------------
694 #if defined FIX8_CODECTIMING
695 void Message::format_codec_timings(const f8String& str, ostream& os, codec_timings& ct)
696 {
697  os << str << ": " << setprecision(9) << ct._cpu_used << " secs, "
698  << setw(8) << right << ct._msg_count << " msgs, "
699  << (ct._cpu_used / ct._msg_count) << " secs/msg, "
700  << setprecision(2) << (ct._msg_count / ct._cpu_used) << " msgs/sec";
701 }
702 
703 void Message::report_codec_timings(const f8String& tag)
704 {
705  ostringstream ostr;
706  ostr.setf(std::ios::showpoint);
707  ostr.setf(std::ios::fixed);
708 
709  ostr << tag << ' ';
710  format_codec_timings("Encode", ostr, _encode_timings);
711  glout_info << ostr.str();
712 
713  ostr.str("");
714  ostr << tag << ' ';
715  format_codec_timings("Decode", ostr, _decode_timings);
716  glout_info << ostr.str();
717 }
718 #endif
719 
720 //-------------------------------------------------------------------------------------------------
721 GroupBase *MessageBase::replace(const unsigned short fnum, GroupBase *with)
722 {
723  GroupBase *old(nullptr);
724  auto itr(_groups.find(fnum));
725  if (itr != _groups.end())
726  {
727  old = itr->second;
728  itr->second = with;
729  }
730  return old;
731 }
732 
F8API unsigned move_legal(MessageBase *to, bool force=false)
Definition: message.cpp:315
const IntervalTimer & Calculate()
Definition: timer.hpp:262
const MsgTable & _bme
Framework generated lookup table to generate Fix messages.
Definition: message.hpp:216
const MessageSpec * find_group(const CommonGroupMap &globmap, int &vers, unsigned tp, uint32_t key)
Definition: f8c.cpp:1554
An outbound message was missing a header or trailer.
FieldTraits _fp
Definition: message.hpp:388
A field was decoded in a message that has already been decoded.
F8API unsigned decode(const f8String &from, unsigned offset, unsigned ignore=0, bool permissive_mode=false)
Definition: message.cpp:87
const unsigned short Common_CheckSum(10)
static unsigned extract_trailer(const f8String &from, f8String &chksum)
Definition: message.cpp:80
const size_t MAX_MSGTYPE_FIELD_LEN(32)
#define FIX8_MAX_FLD_LENGTH
Definition: f8config.h:571
F8API BaseField * remove(const unsigned short fnum, Presence::const_iterator itr)
Definition: message.cpp:646
An inbound message had an invalid (incorrect) checksum.
#define FILE_LINE
Definition: f8utils.hpp:68
virtual F8API void print_field(const unsigned short fnum, std::ostream &os) const
Definition: message.cpp:554
Message instantiation table entry.
Definition: message.hpp:192
An invalid field was decoded.
GroupBase * find_group() const
Definition: message.hpp:792
virtual F8API void print(std::ostream &os, int depth=0) const
Definition: message.cpp:680
bool has(const unsigned short field, Presence::const_iterator &itr) const
Definition: traits.hpp:457
const char * _name
Definition: field.hpp:2078
F8API size_t encode(f8String &to) const
Definition: message.cpp:500
const size_t HEADER_CALC_OFFSET(32)
F8API unsigned copy_legal(MessageBase *to, bool force=false) const
Definition: message.cpp:275
unsigned decode_group(GroupBase *grpbase, const unsigned short fnum, const f8String &from, unsigned s_offset, unsigned ignore)
Definition: message.cpp:166
std::function< Message *(bool)> _do
Definition: message.hpp:176
const Presence & get_presence() const
Definition: traits.hpp:658
F8API unsigned check_positions()
Definition: message.cpp:218
virtual F8API void print_group(const unsigned short fnum, std::ostream &os, int depth=0) const
Definition: message.cpp:536
#define glout_debug
Definition: logger.hpp:614
const char * _name
Definition: message.hpp:195
Abstract base class for all repeating groups.
Definition: message.hpp:59
static unsigned extract_header(const f8String &from, char *len, char *mtype)
Definition: message.cpp:51
virtual MessageBase * create_group(bool deepctor=true) const =0
Used for static trait interrogation.
Definition: traits.hpp:57
const F8MetaCntx & ctx()
Compiler generated metadata object, accessed through this function.
Base exception class.
Definition: f8exception.hpp:49
F8API Message * clone() const
Definition: message.cpp:668
#define FIX8_MAX_MSG_LENGTH
Definition: f8config.h:576
F8API BaseField * replace(const unsigned short fnum, Presence::const_iterator itr, BaseField *with)
Definition: message.cpp:599
#define glout_info
Definition: logger.hpp:601
F8API size_t encode_group(const unsigned short fnum, std::ostream &to) const
Definition: message.cpp:409
An invalid repeating group was found while attempting to encode a message.
const unsigned short Common_BodyLength(9)
A complete Fix message with header, body and trailer.
Definition: message.hpp:1058
static Message * factory(const F8MetaCntx &ctx, const char *from, bool no_chksum=false, bool permissive_mode=false)
Definition: message.hpp:1238
bool get(const unsigned short field, FieldTrait::TraitTypes type=FieldTrait::present) const
Definition: traits.hpp:490
double AsDouble() const
Definition: timer.hpp:278
An invalid message was requested or decoded.
An invalid repeating group field was found while decoding a message (first field is mandatory)...
void check_set_rlm(BaseField *where) const
Definition: message.hpp:526
An invalid field was requested or added.
const unsigned short Common_BeginString(8)
void add_field(const unsigned short fnum, Presence::const_iterator itr, const unsigned pos, BaseField *what, bool check)
Definition: message.hpp:556
The base field class (ABC) for all fields.
Definition: field.hpp:127
static F8API unsigned _tabsize
Definition: message.hpp:408
virtual F8API void print(std::ostream &os, int depth=0) const
Definition: message.cpp:509
F8API size_t encode(std::ostream &to) const
Definition: message.cpp:373
An outbound message was missing a mandatory field.
GroupElement _msgs
vector of repeating messagebase groups
Definition: message.hpp:64
Base class for all fix messages.
Definition: message.hpp:381
const Minst _create
Definition: message.hpp:194
const Val * find_ptr(const Key &key) const
Definition: f8types.hpp:154
Static metadata context class - one per FIX xml schema.
Definition: message.hpp:210
std::string f8String
Definition: f8types.hpp:47
High resolution interval timer.
Definition: timer.hpp:241