//------------------------------------------------------------------------------------------------- unsigned Message::encode(f8String& to) const { char msg[MAX_MSG_LENGTH], hmsg[MAX_MSG_LENGTH]; size_t sz(0), hsz(0); #if defined CODECTIMING ostringstream gerr; gerr << "encode(" << _msgType << "):"; IntervalTimer itm; #endif if (!_header) throw MissingMessageComponent("header"); Fields::const_iterator fitr(_header->_fields.find(Common_MsgType)); static_cast<msg_type *>(fitr->second)->set(_msgType); _header->encode(msg, sz); MessageBase::encode(msg, sz); if (!_trailer) throw MissingMessageComponent("trailer"); _trailer->encode(msg, sz); const unsigned msgLen(sz); // checksummable msglength if ((fitr = _header->_fields.find(Common_BeginString)) == _header->_fields.end()) throw MissingMandatoryField(Common_BeginString); _header->_fp.clear(Common_BeginString, FieldTrait::suppress); fitr->second->encode(hmsg, hsz); #if defined MSGRECYCLING _header->_fp.set(Common_BeginString, FieldTrait::suppress); // in case we want to reuse #endif if ((fitr = _header->_fields.find(Common_BodyLength)) == _header->_fields.end()) throw MissingMandatoryField(Common_BodyLength); _header->_fp.clear(Common_BodyLength, FieldTrait::suppress); static_cast<body_length *>(fitr->second)->set(msgLen); fitr->second->encode(hmsg, hsz); #if defined MSGRECYCLING _header->_fp.set(Common_BodyLength, FieldTrait::suppress); // in case we want to reuse #endif ::memcpy(hmsg + hsz, msg, sz); hsz += sz; if ((fitr = _trailer->_fields.find(Common_CheckSum)) == _trailer->_fields.end()) throw MissingMandatoryField(Common_CheckSum); static_cast<check_sum *>(fitr->second)->set(fmt_chksum(calc_chksum(hmsg, hsz))); _trailer->_fp.clear(Common_CheckSum, FieldTrait::suppress); fitr->second->encode(hmsg, hsz); #if defined MSGRECYCLING _trailer->_fp.set(Common_CheckSum, FieldTrait::suppress); // in case we want to reuse #endif #if defined CODECTIMING gerr << itm.Calculate(); GlobalLogger::log(gerr.str()); #endif to.assign(hmsg, hsz); return to.size(); }
//------------------------------------------------------------------------------------------------- /// Encode message with minimal copying size_t Message::encode(char **hmsg_store) const { char *moffs(*hmsg_store + HEADER_CALC_OFFSET), *msg(moffs); #if defined CODECTIMING IntervalTimer itm; #endif if (!_header) throw MissingMessageComponent("header"); Fields::const_iterator fitr(_header->_fields.find(Common_MsgType)); static_cast<msg_type *>(fitr->second)->set(_msgType); msg += _header->encode(msg); // start msg += MessageBase::encode(msg); if (!_trailer) throw MissingMessageComponent("trailer"); msg += _trailer->encode(msg); const size_t msgLen(msg - moffs); // checksummable msglength const size_t hlen(_ctx._preamble_sz + (msgLen < 10 ? 1 : msgLen < 100 ? 2 : msgLen < 1000 ? 3 : 4)); char *hmsg(moffs - hlen); *hmsg_store = hmsg; if ((fitr = _header->_fields.find(Common_BeginString)) == _header->_fields.end()) throw MissingMandatoryField(Common_BeginString); _header->_fp.clear(Common_BeginString, FieldTrait::suppress); hmsg += fitr->second->encode(hmsg); #if defined MSGRECYCLING _header->_fp.set(Common_BeginString, FieldTrait::suppress); // in case we want to reuse #endif if ((fitr = _header->_fields.find(Common_BodyLength)) == _header->_fields.end()) throw MissingMandatoryField(Common_BodyLength); _header->_fp.clear(Common_BodyLength, FieldTrait::suppress); static_cast<body_length *>(fitr->second)->set(msgLen); hmsg += fitr->second->encode(hmsg); #if defined MSGRECYCLING _header->_fp.set(Common_BodyLength, FieldTrait::suppress); // in case we want to reuse #endif if ((fitr = _trailer->_fields.find(Common_CheckSum)) == _trailer->_fields.end()) throw MissingMandatoryField(Common_CheckSum); static_cast<check_sum *>(fitr->second)->set(fmt_chksum(calc_chksum(moffs - hlen, msgLen + hlen))); _trailer->_fp.clear(Common_CheckSum, FieldTrait::suppress); msg += fitr->second->encode(msg); #if defined MSGRECYCLING _trailer->_fp.set(Common_CheckSum, FieldTrait::suppress); // in case we want to reuse #endif #if defined CODECTIMING _encode_timings._cpu_used += itm.Calculate().AsDouble(); ++_encode_timings._msg_count; #endif *msg = 0; return msg - *hmsg_store; }
//------------------------------------------------------------------------------------------------- unsigned MessageBase::decode_group(const unsigned short fnum, const f8String& from, const unsigned offset) { unsigned s_offset(offset), result; GroupBase *grpbase(find_group(fnum)); if (!grpbase) throw InvalidRepeatingGroup(fnum); const unsigned fsize(from.size()); const char *dptr(from.data()); char tag[MAX_FLD_LENGTH], val[MAX_FLD_LENGTH]; for (bool ok(true); ok && s_offset < fsize; ) { scoped_ptr<MessageBase> grp(grpbase->create_group()); for (unsigned pos(0); s_offset < fsize && (result = extract_element(dptr + s_offset, fsize - s_offset, tag, val));) { const unsigned tv(fast_atoi<unsigned>(tag)); Presence::const_iterator itr(grp->_fp.get_presence().end()); if (grp->_fp.get(tv, itr, FieldTrait::present)) // already present; next group? break; if (pos == 0 && grp->_fp.getPos(tv, itr) != 1) // first field in group is mandatory throw MissingRepeatingGroupField(tv); const BaseEntry *be(_ctx._be.find_ptr(tv)); if (!be) throw InvalidField(tv); if (!grp->_fp.has(tv, itr)) // field not found in sub-group - end of repeats? { ok = false; break; } s_offset += result; grp->add_field(tv, itr, ++pos, be->_create(val, be->_rlm, -1), false); grp->_fp.set(tv, itr, FieldTrait::present); // is present if (grp->_fp.is_group(tv, itr)) // nested group s_offset = grp->decode_group(tv, from, s_offset); } const unsigned short missing(grp->_fp.find_missing()); if (missing) { const BaseEntry& tbe(_ctx._be.find_ref(missing)); ostringstream ostr; ostr << tbe._name << " (" << missing << ')'; throw MissingMandatoryField(ostr.str()); } *grpbase += grp.release(); } return s_offset; }
//------------------------------------------------------------------------------------------------- unsigned MessageBase::decode(const f8String& from, const unsigned offset) { unsigned s_offset(offset), result; const unsigned fsize(from.size()); const char *dptr(from.data()); char tag[MAX_FLD_LENGTH], val[MAX_FLD_LENGTH]; for (unsigned pos(_pos.size()); s_offset <= fsize && (result = extract_element(dptr + s_offset, fsize - s_offset, tag, val));) { const unsigned tv(fast_atoi<unsigned>(tag)); const BaseEntry *be(_ctx._be.find_ptr(tv)); #if defined PERMIT_CUSTOM_FIELDS if (!be && (!_ctx._ube || (be = _ctx._ube->find_ptr(tv)) == 0)) #else if (!be) #endif throw InvalidField(tv); Presence::const_iterator itr(_fp.get_presence().end()); if (!_fp.has(tv, itr)) break; s_offset += result; if (_fp.get(tv, itr, FieldTrait::present)) { if (!_fp.get(tv, itr, FieldTrait::automatic)) throw DuplicateField(tv); } else { add_field(tv, itr, ++pos, be->_create(val, be->_rlm, -1), false); if (_fp.is_group(tv, itr)) s_offset = decode_group(tv, from, s_offset); } } const unsigned short missing(_fp.find_missing()); if (missing) { const BaseEntry& tbe(_ctx._be.find_ref(missing)); ostringstream ostr; ostr << tbe._name << " (" << missing << ')'; throw MissingMandatoryField(ostr.str()); } return s_offset; }