This sample provides a set of customized SBE codecs that can be used to handle BVMF entrypoint messages.
Source code:
SbeB3Codecs.h:
namespace B3 {
#pragma pack(push, 1)
struct MessageHeaderComposite
{
};
struct FramingHeaderComposite
{
void setup(
UInt16 messageOnlySize) {
messageLength = messageOnlySize + sizeof(FramingHeaderComposite);
encodingType = 0xEB50U;
}
};
#pragma pack(pop)
size_t toHexString(char* buffer, const size_t bufferSize, const void* data, const size_t dataSize);
int hexToInt(char x);
size_t fromHexString(void* data, const size_t dataSize, const char* hex, const size_t hexLength);
template<typename T>
{
public:
typedef T DataType;
size_t decode(
SbeFieldDecoderOutput output,
unsigned ,
const void* data,
size_t available) ONIXS_FIXENGINE_OVERRIDE
{
const size_t DataSize = sizeof(DataType);
if (available < DataSize)
throw std::domain_error("Not enough data to decode custom composite");
const DataType* typedData = static_cast<const DataType*>(data);
char content[DataSize*2 + 1];
size_t length = toHexString(content, sizeof(content), typedData, DataSize);
return DataSize;
}
};
template<typename T>
{
public:
typedef T DataType;
SbeWireSize queryFixedSize(
unsigned ) ONIXS_FIXENGINE_OVERRIDE
{
}
{
std::string s;
if (!field.toString(s))
throw std::domain_error("Unable to convert field value to string");
DataType data;
fromHexString(&data, sizeof(DataType), s.c_str(), s.length());
out.put(&data, sizeof(data));
}
};
{
public:
manageCoding.useFormattedDateTime(false);
manageCoding.useValueNamesExternally(false);
}
public:
#pragma pack(push, 1)
struct CustodianInfoLayout
{
void fromString(const StringRef& ref) {
OnixS::B3::fromHexString(this, sizeof(*this), ref.data(), ref.length());
}
};
#pragma pack(pop)
private:
HexStringCompositeDecoder<CustodianInfoLayout> custodianInfoDecoder_;
HexStringCompositeEncoder<CustodianInfoLayout> custodianInfoEncoder_;
public:
#pragma pack(push, 1)
struct InboundBusinessHeader
{
char marketSegmentID;
char padding;
void fromString(const StringRef& ref) {
OnixS::B3::fromHexString(this, sizeof(*this), ref.data(), ref.length());
}
};
#pragma pack(pop)
private:
HexStringCompositeDecoder<InboundBusinessHeader> inboundBusinessHeaderDecoder_;
HexStringCompositeEncoder<InboundBusinessHeader> inboundBusinessHeaderEncoder_;
public:
#pragma pack(push, 1)
struct OutboundBusinessHeader
{
char possResend;
char padding;
void fromString(const StringRef& ref) {
OnixS::B3::fromHexString(this, sizeof(*this), ref.data(), ref.length());
}
};
#pragma pack(pop)
private:
HexStringCompositeDecoder<OutboundBusinessHeader> outboundBusinessHeaderDecoder_;
HexStringCompositeEncoder<OutboundBusinessHeader> outboundBusinessHeaderEncoder_;
public:
#pragma pack(push, 1)
struct BidirectionalBusinessHeader
{
char possResend;
char marketSegmentID;
char padding;
void fromString(const StringRef& ref) {
OnixS::B3::fromHexString(this, sizeof(*this), ref.data(), ref.length());
}
};
#pragma pack(pop)
private:
HexStringCompositeDecoder<BidirectionalBusinessHeader> bidirectionalBusinessHeaderDecoder_;
HexStringCompositeEncoder<BidirectionalBusinessHeader> bidirectionalBusinessHeaderEncoder_;
private:
HexStringCompositeDecoder<FramingHeaderComposite> framingHeaderBusinessHeaderDecoder_;
HexStringCompositeEncoder<FramingHeaderComposite> framingHeaderBusinessHeaderEncoder_;
};
}
}
SbeB3Codecs.cpp:
#include "SbeB3Codecs.h"
namespace B3 {
size_t toHexString(char* buffer, const size_t bufferSize, const void* data, const size_t dataSize) {
if (bufferSize < (dataSize * 2 + 1)) {
throw std::domain_error("Not enough buffer size for hexadecimal encoding.");
}
const char* digits = "0123456789ABCDEF";
size_t counter = dataSize;
for (const unsigned char* p = static_cast<const unsigned char*>(data); counter; --counter) {
char x = digits[(*p) >> 4];
*buffer++ = x;
x = digits[(*p) & 0x0F];
*buffer++ = x;
++p;
}
*buffer = 0;
return dataSize * 2;
}
int hexToInt(char x) {
if (x >= '0' && x <= '9') {
return x - '0';
}
if (x >= 'a' && x <= 'f') {
return 0xA + (x - 'a');
}
if (x >= 'A' && x <= 'F') {
return 0xA + (x - 'A');
}
throw std::domain_error("Not a hexadecimal digit");
}
size_t fromHexString(void* data, const size_t dataSize, const char* hex, const size_t hexLength) {
if (dataSize < hexLength / 2) {
throw std::domain_error("Not enough buffer size for hexadecimal decoding.");
}
if (hexLength % 2) {
throw std::domain_error("The hexadecimal string must be of an even length.");
}
char* dest = static_cast<char*>(data);
for (size_t hLength = hexLength; hLength; hLength -= 2) {
char c = *hex++;
int v = hexToInt(c) << 4;
c = *hex++;
v += hexToInt(c);
*dest++ = v;
}
return hexLength / 2;
}
ISbeFieldDecoder* CodersLibrary::queryDecoder(
CoderOwnerId , SbeFieldMetaData field) {
if (!field.typeMetaData().name().compare("CustodianInfo"))
return &custodianInfoDecoder_;
if (!field.typeMetaData().name().compare("InboundBusinessHeader"))
return &inboundBusinessHeaderDecoder_;
if (!field.typeMetaData().name().compare("OutboundBusinessHeader"))
return &outboundBusinessHeaderDecoder_;
if (!field.typeMetaData().name().compare("BidirectionalBusinessHeader"))
return &bidirectionalBusinessHeaderDecoder_;
if (!field.typeMetaData().name().compare("FramingHeader"))
return &framingHeaderBusinessHeaderDecoder_;
return ONIXS_FIXENGINE_NULLPTR;
}
ISbeFieldEncoder* CodersLibrary::queryEncoder(
CoderOwnerId , SbeFieldMetaData field) {
if (!field.typeMetaData().name().compare("CustodianInfo"))
return &custodianInfoEncoder_;
if (!field.typeMetaData().name().compare("InboundBusinessHeader"))
return &inboundBusinessHeaderEncoder_;
if (!field.typeMetaData().name().compare("OutboundBusinessHeader"))
return &outboundBusinessHeaderEncoder_;
if (!field.typeMetaData().name().compare("BidirectionalBusinessHeader"))
return &bidirectionalBusinessHeaderEncoder_;
if (!field.typeMetaData().name().compare("FramingHeader"))
return &framingHeaderBusinessHeaderEncoder_;
return ONIXS_FIXENGINE_NULLPTR;
}
}
}
SbeB3.cpp:
#include "SbeB3Codecs.h"
#include "../../Common/Helpers.h"
#include "../../Common/Settings.h"
using namespace Settings;
namespace {
void encodeAndDecode();
};
int main(int, const char * [])
{
try {
Engine::init(engineSettings);
encodeAndDecode();
std::cout << "Press Enter to exit." << std::endl;
waitUntilEnterKey();
}
processSampleException(ex.what());
return 3;
}
}
namespace {
char customCompositeHex[256];
OnixS::B3::CodersLibrary::OutboundBusinessHeader businessHeader;
businessHeader.sessionID = 10;
businessHeader.msgSeqNum = 1;
businessHeader.sendingTime = (
UInt64)Timestamp::utc().toUnixNanosecondTimestamp();
businessHeader.possResend = 'Y';
businessHeader.padding = 0;
OnixS::B3::toHexString(customCompositeHex, sizeof(customCompositeHex), &businessHeader, sizeof(businessHeader));
msg.set(35524, customCompositeHex);
msg.set(710, 33);
msg.set(48, 10250);
msg.set(22, '8');
msg.set(207, "BVMF");
msg.set(721, 12345);
msg.set(709, 1);
msg.set(712, 1);
msg.set(722, 9);
msg.set(1003, 37259);
msg.set(713, 43591);
msg.set(581, 39);
msg.set(715, Timestamp::utc().toUnixNanosecondTimestamp() / (86400 * 1000000000LL));
msg.set(60, Timestamp::utc().toUnixNanosecondTimestamp());
msg.set(1, 999);
msg.set(35503, 'T');
msg.set(723, 0);
msg.set(719, 1);
group[0].set(703, 'E');
group[0].set(704, 100);
group[0].set(705, 0);
group[1].set(703, 'E');
group[1].set(704, 0);
group[1].set(705, 110);
msg.set(35510, "Test sample");
msg.set(5149, "Synthetic message");
msg.set(58, "Don't use it in real trading!");
return msg;
}
OnixS::B3::FramingHeaderComposite* getFramingHeader(void* data) {
return static_cast<OnixS::B3::FramingHeaderComposite*>(data);
}
void encodeAndDecode() {
OnixS::B3::CodersLibrary coderLib;
const std::string sbeTemplates = readTextFile("b3-entrypoint-messages-6.4.2.xml");
Dictionary dict = Decoder::generateFixDictionary(sbeTemplates);
Message msg = createPositionMaintenaceReport(dict);
std::cout <<
"Message to encode: " << msg.
toString() << std::endl;
Encoder encoder(sbeTemplates, &coderLib);
const size_t FramingHeaderSize = sizeof(OnixS::B3::FramingHeaderComposite);
unsigned char encodedData[1000];
size_t rootBlockLength = 0;
size_t messageDataSize = encoder.encodeWithHeader(msg, 503, 0, &encodedData[FramingHeaderSize], sizeof(encodedData)- FramingHeaderSize, &rootBlockLength);
OnixS::B3::FramingHeaderComposite *framingHeader = getFramingHeader(encodedData);
framingHeader->setup((
UInt16)messageDataSize);
Decoder decoder(sbeTemplates, dict, &coderLib);
int templateId = 0;
int version = 0;
size_t decodedBytes = 0;
Message decodedMsg = decoder.decode(&encodedData[FramingHeaderSize], messageDataSize, &decodedBytes, &templateId, &version);
std::cout <<
"Decoded message: " << decodedMsg.
toString() << std::endl;
}
};