cpp.IrDecoder.h Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sbe-all Show documentation
Show all versions of sbe-all Show documentation
FIX/SBE - OSI layer 6 presentation for encoding and decoding application messages in binary format for low-latency applications.
/*
* Copyright 2013-2024 Real Logic Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _OTF_IRDECODER_H
#define _OTF_IRDECODER_H
#if defined(WIN32) || defined(_WIN32)
#include
#include
#include
#define fileno _fileno
#define read _read
#define stat _stat64
#else
#include
#include
#include
#include
#endif /* WIN32 */
#include
#include
#include
#include
#include
#include
#include "uk_co_real_logic_sbe_ir_generated/TokenCodec.h"
#include "uk_co_real_logic_sbe_ir_generated/FrameCodec.h"
#include "Token.h"
using namespace sbe::otf;
namespace sbe { namespace otf {
class IrDecoder
{
public:
IrDecoder() = default;
int decode(char *irBuffer, std::uint64_t length)
{
m_length = length;
if (m_length == 0)
{
return -1;
}
std::unique_ptr buffer(new char[m_length]);
m_buffer = std::move(buffer);
std::memcpy(m_buffer.get(), irBuffer, m_length);
return decodeIr();
}
int decode(const char *filename)
{
long long fileSize = getFileSize(filename);
if (fileSize < 0)
{
return -1;
}
m_length = static_cast(fileSize);
if (m_length == 0)
{
return -1;
}
std::unique_ptr buffer(new char[m_length]);
m_buffer = std::move(buffer);
if (readFileIntoBuffer(m_buffer.get(), filename, m_length) < 0)
{
return -1;
}
return decodeIr();
}
std::shared_ptr> header()
{
return m_headerTokens;
}
std::vector>> messages()
{
return m_messages;
}
std::shared_ptr> message(int id, int version)
{
std::shared_ptr> result;
std::for_each(m_messages.begin(), m_messages.end(),
[&](const std::shared_ptr> &tokens)
{
Token &token = tokens->at(0);
if (token.signal() == Signal::BEGIN_MESSAGE &&
token.fieldId() == id &&
token.tokenVersion() <= version)
{
result = tokens;
}
});
return result;
}
std::shared_ptr> message(int id)
{
std::shared_ptr> result;
std::for_each(m_messages.begin(), m_messages.end(),
[&](const std::shared_ptr> &tokens)
{
Token &token = tokens->at(0);
if (token.signal() == Signal::BEGIN_MESSAGE && token.fieldId() == id)
{
result = tokens;
}
});
return result;
}
protected:
// OS specifics
static long long getFileSize(const char *filename)
{
struct stat fileStat{};
if (::stat(filename, &fileStat) != 0)
{
return -1;
}
return fileStat.st_size;
}
static int readFileIntoBuffer(char *buffer, const char *filename, std::uint64_t length)
{
FILE *fptr = ::fopen(filename, "rb");
std::uint64_t remaining = length;
if (nullptr == fptr)
{
return -1;
}
int fd = fileno(fptr);
while (remaining > 0)
{
auto bytes = static_cast(4098 < remaining ? 4098 : remaining);
long long sz = ::read(fd, buffer + (length - remaining), bytes);
remaining -= sz;
if (sz < 0)
{
break;
}
}
fclose(fptr);
return remaining == 0 ? 0 : -1;
}
private:
std::shared_ptr> m_headerTokens;
std::vector>> m_messages;
std::unique_ptr m_buffer;
std::uint64_t m_length = 0;
int m_id = 0;
int decodeIr()
{
using namespace uk::co::real_logic::sbe::ir::generated;
FrameCodec frame;
std::uint64_t offset = 0;
char tmp[256] = {};
frame.wrapForDecode(
m_buffer.get(),
offset,
FrameCodec::sbeBlockLength(),
FrameCodec::sbeSchemaVersion(),
m_length);
frame.getPackageName(tmp, sizeof(tmp));
if (frame.irVersion() != 0)
{
return -1;
}
frame.getNamespaceName(tmp, sizeof(tmp));
frame.getSemanticVersion(tmp, sizeof(tmp));
offset += frame.encodedLength();
m_headerTokens.reset(new std::vector());
std::uint64_t headerLength = readHeader(offset);
m_id = frame.irId();
offset += headerLength;
while (offset < m_length)
{
offset += readMessage(offset);
}
return 0;
}
std::uint64_t decodeAndAddToken(std::shared_ptr> &tokens, std::uint64_t offset)
{
using namespace uk::co::real_logic::sbe::ir::generated;
TokenCodec tokenCodec;
tokenCodec.wrapForDecode(
m_buffer.get(),
offset,
TokenCodec::sbeBlockLength(),
TokenCodec::sbeSchemaVersion(),
m_length);
auto signal = static_cast(tokenCodec.signal());
auto type = static_cast(tokenCodec.primitiveType());
auto presence = static_cast(tokenCodec.presence());
auto byteOrder = static_cast(tokenCodec.byteOrder());
std::int32_t tokenOffset = tokenCodec.tokenOffset();
std::int32_t tokenSize = tokenCodec.tokenSize();
std::int32_t id = tokenCodec.fieldId();
std::int32_t version = tokenCodec.tokenVersion();
std::int32_t componentTokenCount = tokenCodec.componentTokenCount();
char tmpBuffer[256] = {};
std::uint64_t tmpLen = 0;
tmpLen = tokenCodec.getName(tmpBuffer, sizeof(tmpBuffer));
std::string name(tmpBuffer, static_cast(tmpLen));
tmpLen = tokenCodec.getConstValue(tmpBuffer, sizeof(tmpBuffer));
PrimitiveValue constValue(type, tmpLen, tmpBuffer);
tmpLen = tokenCodec.getMinValue(tmpBuffer, sizeof(tmpBuffer));
PrimitiveValue minValue(type, tmpLen, tmpBuffer);
tmpLen = tokenCodec.getMaxValue(tmpBuffer, sizeof(tmpBuffer));
PrimitiveValue maxValue(type, tmpLen, tmpBuffer);
tmpLen = tokenCodec.getNullValue(tmpBuffer, sizeof(tmpBuffer));
PrimitiveValue nullValue(type, tmpLen, tmpBuffer);
tmpLen = tokenCodec.getCharacterEncoding(tmpBuffer, sizeof(tmpBuffer));
std::string characterEncoding(tmpBuffer, tmpLen);
tmpLen = tokenCodec.getEpoch(tmpBuffer, sizeof(tmpBuffer));
std::string epoch(tmpBuffer, tmpLen);
tmpLen = tokenCodec.getTimeUnit(tmpBuffer, sizeof(tmpBuffer));
std::string timeUnit(tmpBuffer, tmpLen);
tmpLen = tokenCodec.getSemanticType(tmpBuffer, sizeof(tmpBuffer));
std::string semanticType(tmpBuffer, tmpLen);
tmpLen = tokenCodec.getDescription(tmpBuffer, sizeof(tmpBuffer));
std::string description(tmpBuffer, tmpLen);
tmpLen = tokenCodec.getReferencedName(tmpBuffer, sizeof(tmpBuffer));
std::string referencedName(tmpBuffer, tmpLen);
Encoding encoding(
type,
presence,
byteOrder,
minValue,
maxValue,
nullValue,
constValue,
characterEncoding,
epoch,
timeUnit,
semanticType);
Token token(tokenOffset, id, version, tokenSize, componentTokenCount, signal, name, description, encoding);
tokens->push_back(token);
return tokenCodec.encodedLength();
}
std::uint64_t readHeader(std::uint64_t offset)
{
std::uint64_t size = 0;
while (offset + size < m_length)
{
size += decodeAndAddToken(m_headerTokens, offset + size);
Token &token = m_headerTokens->back();
if (token.signal() == Signal::END_COMPOSITE)
{
break;
}
}
return size;
}
std::uint64_t readMessage(std::uint64_t offset)
{
std::uint64_t size = 0;
std::shared_ptr> tokensForMessage(new std::vector());
while (offset + size < m_length)
{
size += decodeAndAddToken(tokensForMessage, offset + size);
Token &token = tokensForMessage->back();
if (token.signal() == Signal::END_MESSAGE)
{
break;
}
}
m_messages.push_back(tokensForMessage);
return size;
}
};
}}
#endif