This sample provides a set of customized SBE codecs that can be used to handle BVMF entrypoint messages.
Source code:
- SbeB3Codecs.h
 
- SbeB3Codecs.cpp
 
- SbeB3.cpp
 
SbeB3Codecs.h: 
 
 
namespace B3 {
 
using namespace OnixS::FIX;
using namespace OnixS::FIX::SBE;
 
#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>
class HexStringCompositeDecoder : public ISbeFieldDecoder
{
public:
    typedef T DataType;
    {
        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);
 
        output.set(content, (SbeWireSize)length);
        return DataSize;
    }
};
template<typename T>
class HexStringCompositeEncoder : public ISbeFieldEncoder
{
public:
    typedef T DataType;
 
    {
        return (SbeWireSize)sizeof(DataType);
    }
 
    {
        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));
    }
};
class CodersLibrary : public ISbeCustomCoderLibrary
{
public:
    void queryCodingControl(CoderOwnerId , SbeFieldMetaData ,
        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_;
}
 
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_;
}
 
}
}
 
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 {
 
 
        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.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(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");
 
    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;
 
 
}
 
};