/* * 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_MESSAGEDECODER_H #define _OTF_MESSAGEDECODER_H #include #include #include "Token.h" using namespace sbe::otf; namespace sbe { namespace otf { namespace OtfMessageDecoder { typedef std::function on_begin_message_t; typedef std::function on_end_message_t; typedef std::function on_encoding_t; typedef std::function &tokens, std::size_t fromIndex, std::size_t toIndex, std::uint64_t actingVersion)> on_enum_t; typedef std::function &tokens, std::size_t fromIndex, std::size_t toIndex, std::uint64_t actingVersion)> on_bit_set_t; typedef std::function &tokens, std::size_t fromIndex, std::size_t toIndex)> on_begin_composite_t; typedef std::function &tokens, std::size_t fromIndex, std::size_t toIndex)> on_end_composite_t; typedef std::function on_group_header_t; typedef std::function on_begin_group_t; typedef std::function on_end_group_t; typedef std::function on_var_data_t; class BasicTokenListener { public: virtual void onBeginMessage(Token &token) {} virtual void onEndMessage(Token &token) {} virtual void onEncoding( Token &fieldToken, const char *buffer, Token &typeToken, std::uint64_t actingVersion) {} virtual void onEnum( Token &fieldToken, const char *buffer, std::vector &tokens, std::size_t fromIndex, std::size_t toIndex, std::uint64_t actingVersion) {} virtual void onBitSet( Token &fieldToken, const char *buffer, std::vector &tokens, std::size_t fromIndex, std::size_t toIndex, std::uint64_t actingVersion) {} virtual void onBeginComposite( Token &fieldToken, std::vector &tokens, std::size_t fromIndex, std::size_t toIndex) {} virtual void onEndComposite( Token &fieldToken, std::vector &tokens, std::size_t fromIndex, std::size_t toIndex) {} virtual void onGroupHeader( Token &token, std::uint64_t numInGroup) {} virtual void onBeginGroup( Token &token, std::uint64_t groupIndex, std::uint64_t numInGroup) {} virtual void onEndGroup( Token &token, std::uint64_t groupIndex, std::uint64_t numInGroup) {} virtual void onVarData( Token &fieldToken, const char *buffer, std::uint64_t length, Token &typeToken) {} }; template static void decodeComposite( Token &fieldToken, const char *buffer, std::size_t bufferIndex, std::size_t length, std::shared_ptr> tokens, size_t tokenIndex, size_t toIndex, std::uint64_t actingVersion, TokenListener &listener) { listener.onBeginComposite(fieldToken, *tokens, tokenIndex, toIndex); for (size_t i = tokenIndex + 1; i < toIndex;) { Token &token = tokens->at(i); const size_t nextFieldIndex = i + token.componentTokenCount(); const auto offset = static_cast(token.offset()); switch (token.signal()) { case Signal::BEGIN_COMPOSITE: decodeComposite( fieldToken, buffer, bufferIndex + offset, length, tokens, i, nextFieldIndex - 1, actingVersion, listener); break; case Signal::BEGIN_ENUM: listener.onEnum( fieldToken, buffer + bufferIndex + offset, *tokens, i, nextFieldIndex - 1, actingVersion); break; case Signal::BEGIN_SET: listener.onBitSet( fieldToken, buffer + bufferIndex + offset, *tokens, i, nextFieldIndex - 1, actingVersion); break; case Signal::ENCODING: listener.onEncoding(token, buffer + bufferIndex + offset, token, actingVersion); break; default: throw std::runtime_error("incorrect signal type in decodeComposite"); } i += token.componentTokenCount(); } listener.onEndComposite(fieldToken, *tokens, tokenIndex, toIndex); } template static size_t decodeFields( const char *buffer, std::size_t bufferIndex, std::size_t length, std::uint64_t actingVersion, std::shared_ptr> tokens, size_t tokenIndex, const size_t numTokens, TokenListener &listener) { while (tokenIndex < numTokens) { Token &fieldToken = tokens->at(tokenIndex); if (Signal::BEGIN_FIELD != fieldToken.signal()) { break; } const size_t nextFieldIndex = tokenIndex + fieldToken.componentTokenCount(); tokenIndex++; Token& typeToken = tokens->at(tokenIndex); const std::size_t offset = bufferIndex + typeToken.offset(); switch (typeToken.signal()) { case Signal::BEGIN_COMPOSITE: decodeComposite( fieldToken, buffer, offset, length, tokens, tokenIndex, nextFieldIndex - 2, actingVersion, listener); break; case Signal::BEGIN_ENUM: listener.onEnum(fieldToken, buffer + offset, *tokens, tokenIndex, nextFieldIndex - 2, actingVersion); break; case Signal::BEGIN_SET: listener.onBitSet(fieldToken, buffer + offset, *tokens, tokenIndex, nextFieldIndex - 2, actingVersion); break; case Signal::ENCODING: listener.onEncoding(fieldToken, buffer + offset, typeToken, actingVersion); break; default: throw std::runtime_error("incorrect signal type in decodeFields"); } tokenIndex = nextFieldIndex; } return tokenIndex; } template std::size_t decodeData( const char *buffer, std::size_t bufferIndex, const std::size_t length, const std::shared_ptr> &tokens, std::size_t tokenIndex, const std::size_t numTokens, std::uint64_t actingVersion, TokenListener &listener) { while (tokenIndex < numTokens) { Token &token = tokens->at(tokenIndex); if (Signal::BEGIN_VAR_DATA != token.signal()) { break; } const bool isPresent = token.tokenVersion() <= static_cast(actingVersion); Token &lengthToken = tokens->at(tokenIndex + 2); Token &dataToken = tokens->at(tokenIndex + 3); if ((bufferIndex + dataToken.offset()) > length) { throw std::runtime_error("length too short for data length field"); } std::uint64_t dataLength = isPresent ? lengthToken.encoding().getAsUInt(buffer + bufferIndex + lengthToken.offset()) : 0; if (isPresent) { bufferIndex += dataToken.offset(); } if ((bufferIndex + dataLength) > length) { throw std::runtime_error("length too short for data field"); } listener.onVarData(token, buffer + bufferIndex, dataLength, dataToken); bufferIndex += dataLength; tokenIndex += token.componentTokenCount(); } return bufferIndex; } template std::pair decodeGroups( const char *buffer, std::size_t bufferIndex, const std::size_t length, std::uint64_t actingVersion, std::shared_ptr> tokens, size_t tokenIndex, const size_t numTokens, TokenListener &listener) { while (tokenIndex < numTokens) { Token& token = tokens->at(tokenIndex); if (Signal::BEGIN_GROUP != token.signal()) { break; } const bool isPresent = token.tokenVersion() <= static_cast(actingVersion); Token &dimensionsTypeComposite = tokens->at(tokenIndex + 1); auto dimensionsLength = static_cast(dimensionsTypeComposite.encodedLength()); if ((bufferIndex + dimensionsLength) > length) { throw std::runtime_error("length too short for group dimensions"); } Token &blockLengthToken = tokens->at(tokenIndex + 2); Token &numInGroupToken = tokens->at(tokenIndex + 3); std::uint64_t blockLength = isPresent ? blockLengthToken.encoding().getAsUInt(buffer + bufferIndex + blockLengthToken.offset()) : 0; std::uint64_t numInGroup = isPresent ? numInGroupToken.encoding().getAsUInt(buffer + bufferIndex + numInGroupToken.offset()) : 0; if (isPresent) { bufferIndex += dimensionsLength; } size_t beginFieldsIndex = tokenIndex + dimensionsTypeComposite.componentTokenCount() + 1; listener.onGroupHeader(token, numInGroup); for (std::uint64_t i = 0; i < numInGroup; i++) { listener.onBeginGroup(token, i, numInGroup); if ((bufferIndex + blockLength) > length) { throw std::runtime_error("length too short for group blockLength"); } size_t afterFieldsIndex = decodeFields( buffer, bufferIndex, length, actingVersion, tokens, beginFieldsIndex, numTokens, listener); bufferIndex += blockLength; std::pair groupsResult = decodeGroups( buffer, bufferIndex, length, actingVersion, tokens, afterFieldsIndex, numTokens, listener); bufferIndex = decodeData( buffer, groupsResult.first, length, tokens, groupsResult.second, numTokens, actingVersion, listener); listener.onEndGroup(token, i, numInGroup); } tokenIndex += token.componentTokenCount(); } return { bufferIndex, tokenIndex }; } /** * Entry point for decoder. */ template std::size_t decode( const char *buffer, const std::size_t length, std::uint64_t actingVersion, size_t blockLength, std::shared_ptr> msgTokens, TokenListener &listener) { listener.onBeginMessage(msgTokens->at(0)); if (length < blockLength) { throw std::runtime_error("length too short for message blockLength"); } size_t numTokens = msgTokens->size(); const size_t tokenIndex = decodeFields(buffer, 0, length, actingVersion, msgTokens, 1, numTokens, listener); size_t bufferIndex = blockLength; std::pair groupResult = decodeGroups( buffer, bufferIndex, length, actingVersion, msgTokens, tokenIndex, numTokens, listener); bufferIndex = decodeData( buffer, groupResult.first, length, msgTokens, groupResult.second, numTokens, actingVersion, listener); listener.onEndMessage(msgTokens->at(numTokens - 1)); return bufferIndex; } }}} #endif