OnixS C++ FIX Engine  4.3.0
API Documentation
SBE Protocol Decoding and Encoding using Message object

Encoding FIX Messages

To encode a FIX message into a SBE stream, the OnixS::FIX::SBE::Encoder class is used.

using namespace OnixS::FIX;
using namespace OnixS::FIX::SBE;
std::string xmlSbeTemplate = readTextFile("SbeTemplate.xml");
Encoder encoder(xmlSbeTemplate);
const int SbeTemplateID = 10; // Identifier of the SBE template, that have to be used to encode the message
const int SbeSchemaVersion = encoder.schemaVersion();
const size_t BufferSize = 1024;
unsigned char sbeStreamChunk[BufferSize];
size_t rootBlockLength = 0;
size_t chunkSize = encoder.encode(sourceFixMessage, SbeTemplateID, SbeSchemaVersion, sbeStreamChunk, BufferSize, &rootBlockLength);

Decoding SBE binary chunks

To decode a part of a SBE stream back into a FIX message, the OnixS::FIX::SBE::Decoder class is used.

Please note, that it is needed to obtain three separate values for:

Usually, the data arranged in the message header. Decoding of the header is not covered by the SBE decoder, and the header has to be decoded by separate user code.

void sbeDecoding()
{
using namespace OnixS::FIX;
EngineSettings settings;
settings.listenPort(-1)
.dictionaryFile("dictionaries/FixDictionary.xml");
Engine::init(settings);
std::ifstream templatesStream("templates/SbeTemplates.xml");
assert(templatesStream);
const std::string XmlSbeTemplates((std::istreambuf_iterator<char>(templatesStream)), std::istreambuf_iterator<char>());
assert(!XmlSbeTemplates.empty());
Dictionary dictionary("DICT1");
SBE::Decoder decoder(XmlSbeTemplates, dictionary);
std::ifstream dataStream("data/sbeChunk.bin", std::ios_base::in | std::ios_base::binary);
assert(dataStream);
const std::string binaryChunk((std::istreambuf_iterator<char>(dataStream)), std::istreambuf_iterator<char>());
assert(!binaryChunk.empty());
// Following values declared as constant for illustration purposes only.
// Normally they are obtained from the data stream.
const int TemplateId = 10;
const int Version = schemaVersion();
const size_t RootBlockLength = 28;
const Message& message = decoder.decode(TemplateId, Version, RootBlockLength, reinterpret_cast<const unsigned char*>(binaryChunk.data()), binaryChunk.size());
std::clog << "Decoded: " << message << std::endl;
}

Decoding multiple FIX Messages from the same binary chunk.

To decode multiple FIX Messages from the same binary chunk the OnixS::FIX::SBE::Decoder::tryDecode method is used.

Note
Exact code of header decoding can vary in dependency on the specification of the protocol used.
using namespace OnixS::FIX;
// Suppose the message header can be represented by the following structure
struct SbeMessageHeader
{
int templateId;
int schemaVersion;
unsigned rootBlockSize;
};
void sbeDecodeMultipleMessagesFromSameBinaryChunk()
{
EngineSettings settings;
settings.listenPort(-1)
.dictionaryFile("dictionaries/FixDictionary.xml");
Engine::init(settings);
std::ifstream templatesStream("templates/SbeTemplates.xml");
assert(templatesStream);
const std::string XmlSbeTemplates((std::istreambuf_iterator<char>(templatesStream)), std::istreambuf_iterator<char>());
assert(!XmlSbeTemplates.empty());
Dictionary dictionary("DICT1");
SBE::Decoder decoder(XmlSbeTemplates, dictionary);
std::ifstream dataStream("data/sbeChunk.bin", std::ios_base::in | std::ios_base::binary);
assert(dataStream);
const std::string BinaryChunk((std::istreambuf_iterator<char>(dataStream)), std::istreambuf_iterator<char>());
assert(!BinaryChunk.empty());
// Simple decoding of the header. Only for illustration purposes.
const SbeMessageHeader *header = reinterpret_cast<const SbeMessageHeader *>(&BinaryChunk[0]);
size_t offset = sizeof(SbeMessageHeader);
size_t count = BinaryChunk.length() - sizeof(SbeMessageHeader);
Message message;
size_t numberOfDecodedBytes = 0;
while (decoder.tryDecode(header->templateId, header->schemaVersion, header->rootBlockSize, reinterpret_cast<const unsigned char*>(BinaryChunk.data()), offset, count, &message, &numberOfDecodedBytes))
{
std::clog << "Decoded " << numberOfDecodedBytes << " bytes: " << message << std::endl;
offset += numberOfDecodedBytes;
count -= numberOfDecodedBytes;
if (count <= sizeof(SbeMessageHeader))
break;
count -= sizeof(SbeMessageHeader);
// Decode header for the next message
header = reinterpret_cast<const SbeMessageHeader *>(&BinaryChunk[offset]);
offset += sizeof(SbeMessageHeader); // Step over the header
}
}