#ifndef FIX_MESSAGE
#define FIX_MESSAGE
#ifdef _MSC_VER
#pragma warning(disable : 4786)
#endif
#include "DataDictionary.h"
#include "FieldMap.h"
#include "Fields.h"
#include "Group.h"
#include "SessionID.h"
#include "Values.h"
#include <memory>
#include <vector>
namespace FIX {
class Header : public FieldMap {
enum {
REQUIRED_FIELDS = 8
};
public:
Header()
: FieldMap(message_order(message_order::header), REQUIRED_FIELDS) {}
Header(const message_order &order)
: FieldMap(order) {}
void addGroup(const FIX::Group &group) { FieldMap::addGroup(group.field(), group); }
void replaceGroup(unsigned num, const FIX::Group &group) { FieldMap::replaceGroup(num, group.field(), group); }
Group &getGroup(unsigned num, FIX::Group &group) const EXCEPT(FieldNotFound) {
group.clear();
return static_cast<Group &>(FieldMap::getGroup(num, group.field(), group));
}
void removeGroup(unsigned num, const FIX::Group &group) { FieldMap::removeGroup(num, group.field()); }
void removeGroup(const FIX::Group &group) { FieldMap::removeGroup(group.field()); }
bool hasGroup(const FIX::Group &group) const { return FieldMap::hasGroup(group.field()); }
bool hasGroup(unsigned num, const FIX::Group &group) const { return FieldMap::hasGroup(num, group.field()); }
};
class Trailer : public FieldMap {
enum {
REQUIRED_FIELDS = 1
};
public:
Trailer()
: FieldMap(message_order(message_order::trailer), REQUIRED_FIELDS) {}
Trailer(const message_order &order)
: FieldMap(order) {}
void addGroup(const FIX::Group &group) { FieldMap::addGroup(group.field(), group); }
void replaceGroup(unsigned num, const FIX::Group &group) { FieldMap::replaceGroup(num, group.field(), group); }
Group &getGroup(unsigned num, FIX::Group &group) const EXCEPT(FieldNotFound) {
group.clear();
return static_cast<Group &>(FieldMap::getGroup(num, group.field(), group));
}
void removeGroup(unsigned num, const FIX::Group &group) { FieldMap::removeGroup(num, group.field()); }
void removeGroup(const FIX::Group &group) { FieldMap::removeGroup(group.field()); }
bool hasGroup(const FIX::Group &group) const { return FieldMap::hasGroup(group.field()); }
bool hasGroup(unsigned num, const FIX::Group &group) const { return FieldMap::hasGroup(num, group.field()); }
};
class Message : public FieldMap {
friend class DataDictionary;
friend class Session;
enum field_type {
header,
body,
trailer
};
public:
Message();
Message(const message_order &hdrOrder, const message_order &trlOrder, const message_order &order);
Message(const std::string &string, bool validate = true) EXCEPT(InvalidMessage);
Message(const std::string &string, const FIX::DataDictionary &dataDictionary, bool validate = true)
EXCEPT(InvalidMessage);
Message(
const std::string &string,
const FIX::DataDictionary &sessionDataDictionary,
const FIX::DataDictionary &applicationDataDictionary,
bool validate = true) EXCEPT(InvalidMessage);
Message(
const message_order &headerOrder,
const message_order &trailerOrder,
const message_order &order,
const std::string &string,
const FIX::DataDictionary &dataDictionary,
bool validate = true) EXCEPT(InvalidMessage);
Message(
const message_order &headerOrder,
const message_order &trailerOrder,
const message_order &order,
const std::string &string,
const FIX::DataDictionary &sessionDataDictionary,
const FIX::DataDictionary &applicationDataDictionary,
bool validate = true) EXCEPT(InvalidMessage);
Message(const Message &) = default;
Message(Message &&) = default;
~Message();
Message &operator=(const Message &) = default;
Message &operator=(Message &&) = default;
static bool InitializeXML(const std::string &string);
void addGroup(const FIX::Group &group) { FieldMap::addGroup(group.field(), group); }
void replaceGroup(unsigned num, const FIX::Group &group) { FieldMap::replaceGroup(num, group.field(), group); }
Group &getGroup(unsigned num, FIX::Group &group) const EXCEPT(FieldNotFound) {
group.clear();
return static_cast<Group &>(FieldMap::getGroup(num, group.field(), group));
}
void removeGroup(unsigned num, const FIX::Group &group) { FieldMap::removeGroup(num, group.field()); }
void removeGroup(const FIX::Group &group) { FieldMap::removeGroup(group.field()); }
bool hasGroup(const FIX::Group &group) const { return FieldMap::hasGroup(group.field()); }
bool hasGroup(unsigned num, const FIX::Group &group) const { return FieldMap::hasGroup(num, group.field()); }
protected:
Message(const BeginString &beginString, const MsgType &msgType);
public:
std::string toString(
int beginStringField = FIELD::BeginString,
int bodyLengthField = FIELD::BodyLength,
int checkSumField = FIELD::CheckSum) const;
std::string &toString(
std::string &,
int beginStringField = FIELD::BeginString,
int bodyLengthField = FIELD::BodyLength,
int checkSumField = FIELD::CheckSum) const;
std::string toXML() const;
std::string &toXML(std::string &) const;
void reverseRoute(const Header &);
void setString(const std::string &string) EXCEPT(InvalidMessage) { setString(string, true); }
void setString(const std::string &string, bool validate) EXCEPT(InvalidMessage) { setString(string, validate, 0); }
void setString(const std::string &string, bool validate, const FIX::DataDictionary *pDataDictionary)
EXCEPT(InvalidMessage) {
setString(string, validate, pDataDictionary, pDataDictionary);
}
void setString(
const std::string &string,
bool validate,
const FIX::DataDictionary *pSessionDataDictionary,
const FIX::DataDictionary *pApplicationDataDictionary) EXCEPT(InvalidMessage);
void setGroup(
const std::string &msg,
const FieldBase &field,
const std::string &string,
std::string::size_type &pos,
FieldMap &map,
const DataDictionary &dataDictionary);
bool setStringHeader(const std::string &string);
const Header &getHeader() const { return m_header; }
Header &getHeader() { return m_header; }
const Trailer &getTrailer() const { return m_trailer; }
Trailer &getTrailer() { return m_trailer; }
bool hasValidStructure(int &tag) const {
tag = m_tag;
return m_validStructure;
}
int bodyLength(
int beginStringField = FIELD::BeginString,
int bodyLengthField = FIELD::BodyLength,
int checkSumField = FIELD::CheckSum) const {
return m_header.calculateLength(beginStringField, bodyLengthField, checkSumField)
+ calculateLength(beginStringField, bodyLengthField, checkSumField)
+ m_trailer.calculateLength(beginStringField, bodyLengthField, checkSumField);
}
int checkSum(int checkSumField = FIELD::CheckSum) const {
return (m_header.calculateTotal(checkSumField) + calculateTotal(checkSumField)
+ m_trailer.calculateTotal(checkSumField))
% 256;
}
bool isAdmin() const {
MsgType msgType;
if (m_header.getFieldIfSet(msgType)) {
return isAdminMsgType(msgType);
}
return false;
}
bool isApp() const {
MsgType msgType;
if (m_header.getFieldIfSet(msgType)) {
return !isAdminMsgType(msgType);
}
return false;
}
bool isEmpty() { return m_header.isEmpty() && FieldMap::isEmpty() && m_trailer.isEmpty(); }
void clear() {
m_tag = 0;
m_validStructure = true;
m_header.clear();
FieldMap::clear();
m_trailer.clear();
}
static bool isAdminMsgType(const MsgType &msgType) {
if (msgType.getValue().length() != 1) {
return false;
}
return strchr("0A12345", msgType.getValue().c_str()[0]) != 0;
}
static ApplVerID toApplVerID(const BeginString &value) {
if (value == BeginString_FIX40) {
return ApplVerID(ApplVerID_FIX40);
}
if (value == BeginString_FIX41) {
return ApplVerID(ApplVerID_FIX41);
}
if (value == BeginString_FIX42) {
return ApplVerID(ApplVerID_FIX42);
}
if (value == BeginString_FIX43) {
return ApplVerID(ApplVerID_FIX43);
}
if (value == BeginString_FIX44) {
return ApplVerID(ApplVerID_FIX44);
}
if (value == BeginString_FIX50) {
return ApplVerID(ApplVerID_FIX50);
}
if (value == "FIX.5.0SP1") {
return ApplVerID(ApplVerID_FIX50_SP1);
}
if (value == "FIX.5.0SP2") {
return ApplVerID(ApplVerID_FIX50_SP2);
}
return ApplVerID(ApplVerID(value));
}
static BeginString toBeginString(const ApplVerID &applVerID) {
if (applVerID == ApplVerID_FIX40) {
return BeginString(BeginString_FIX40);
} else if (applVerID == ApplVerID_FIX41) {
return BeginString(BeginString_FIX41);
} else if (applVerID == ApplVerID_FIX42) {
return BeginString(BeginString_FIX42);
} else if (applVerID == ApplVerID_FIX43) {
return BeginString(BeginString_FIX43);
} else if (applVerID == ApplVerID_FIX44) {
return BeginString(BeginString_FIX44);
} else if (applVerID == ApplVerID_FIX50) {
return BeginString(BeginString_FIX50);
} else if (applVerID == ApplVerID_FIX50_SP1) {
return BeginString(BeginString_FIX50);
} else if (applVerID == ApplVerID_FIX50_SP2) {
return BeginString(BeginString_FIX50);
} else {
return BeginString("");
}
}
static bool isHeaderField(int field);
static bool isHeaderField(const FieldBase &field, const DataDictionary *pD = 0);
static bool isHeaderField(int field, const DataDictionary *pD);
static bool isTrailerField(int field);
static bool isTrailerField(const FieldBase &field, const DataDictionary *pD = 0);
static bool isTrailerField(int field, const DataDictionary *pD);
SessionID getSessionID(const std::string &qualifier = "") const EXCEPT(FieldNotFound);
void setSessionID(const SessionID &sessionID);
private:
FieldBase extractField(
const std::string &string,
std::string::size_type &pos,
const DataDictionary *pSessionDD = 0,
const DataDictionary *pAppDD = 0,
const Group *pGroup = 0) const;
static bool IsDataField(int field, const DataDictionary *pSessionDD, const DataDictionary *pAppDD) {
if ((pSessionDD && pSessionDD->isDataField(field))
|| (pAppDD && pAppDD != pSessionDD && pAppDD->isDataField(field))) {
return true;
}
return false;
}
void validate() const;
std::string toXMLFields(const FieldMap &fields, int space) const;
protected:
mutable Header m_header;
mutable Trailer m_trailer;
bool m_validStructure;
int m_tag;
static std::unique_ptr<DataDictionary> s_dataDictionary;
};
inline std::ostream &operator<<(std::ostream &stream, const Message &message) {
std::string str;
stream << message.toString(str);
return stream;
}
inline MsgType identifyType(const std::string &message) EXCEPT(MessageParseError) {
std::string::size_type pos = message.find("\001"
"35=");
if (pos == std::string::npos) {
throw MessageParseError();
}
std::string::size_type startValue = pos + 4;
std::string::size_type soh = message.find_first_of('\001', startValue);
if (soh == std::string::npos) {
throw MessageParseError();
}
std::string value = message.substr(startValue, soh - startValue);
return MsgType(value);
}
}
#endif