X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?p=sim%2Fe2-interface.git;a=blobdiff_plain;f=e2sim%2Fe2apv1sim%2Fsrc%2FASN1%2Fasn%2Fber%2Fcodec.hpp;fp=e2sim%2Fe2apv1sim%2Fsrc%2FASN1%2Fasn%2Fber%2Fcodec.hpp;h=3a42ad56fb4b16f3720e5fc70421e20153b30538;hp=0000000000000000000000000000000000000000;hb=0eba05c4ff0c99974d3f3a63b65cbe2adb209e51;hpb=c380e183231711cf9f8bc72d0eb52e532dd07085 diff --git a/e2sim/e2apv1sim/src/ASN1/asn/ber/codec.hpp b/e2sim/e2apv1sim/src/ASN1/asn/ber/codec.hpp new file mode 100755 index 0000000..3a42ad5 --- /dev/null +++ b/e2sim/e2apv1sim/src/ASN1/asn/ber/codec.hpp @@ -0,0 +1,931 @@ +#pragma once +/****************************************************************************** +* +* Copyright (c) 2019 AT&T Intellectual Property. +* Copyright (c) 2018-2019 Nokia. +* +* 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 +* +* http://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. +* +******************************************************************************/ + +// Standard Includes: ANSI C/C++, MSA, and Third-Party Libraries + +// Local Includes: Application specific classes, functions, and libraries +#include "asn/elements.hpp" +#include "asn/ber/common.hpp" +#include "asn/ber/context.hpp" +#include "asn/ber/tag.hpp" +#include "asn/ber/length.hpp" +#include "asn/ber/visitor.hpp" +#include "asn/ber/opentype.hpp" + +namespace asn { +namespace ber { + +/******************************************************************************** +pack (X.690) +*********************************************************************************/ +template +bool pack(IE const& ie, EncoderCtx& ctx) +{ + ctx.refErrorCtx().reset(); + Element::run(ie, ctx); + + if (ctx) + Tools::bit_accessor::padByte(ctx.refBuffer()); + + return static_cast(ctx); +} +/******************************************************************************** +unpack (X.690) +*********************************************************************************/ +template +bool unpack(IE& ie, DecoderCtx& ctx) +{ + Element::run(ie, ctx); + + if (ctx) + Tools::bit_accessor::padByte(ctx.refBuffer()); + + if(ctx && ctx.refBuffer().getBytesLeft()) + { + ctx.ie_name(IE::name()); + ctx.refErrorCtx().lengthErrorBytes(ctx.refBuffer().getBytesLeft(), 0); + } + + return static_cast(ctx); +} + +/*************************************************************************************** +* ElementType +***************************************************************************************/ +template +struct ElementType; + +/*************************************************************************************** +* ExplicitCodec: Codec for elements with EXPLICIT tag +***************************************************************************************/ +template +struct ExplicitCodec +{ + using tag_t = Tag; + static bool inline is_matched(tag_value_t _tag) {return _tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + auto & buffer = ctx.refBuffer(); + + tag_t::encode(ctx); + u8* len_ptr = buffer.advance(1); //reserve for the length + + Element::run(static_cast(ie), ctx); + + size_t len = buffer.begin() - len_ptr - 1; + if(len > 127) + { + len_ptr[0] = 0x80; //undefinite length form per X.690 8.1.3.6 + uint8_t buff[2] = {0}; // end-of-contents octets (X.690 8.1.5) + buffer.putBytes(buff, sizeof(buff)); + } + else + { + len_ptr[0] = static_cast(len); //one byte form per X.690 8.1.3.4 + } + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + if(tag_t::value() != tag) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + auto & buffer = ctx.refBuffer(); + size_t length = Length::decode(ctx); + + ASN_DECODER_TRACE("EX buffer: %s", static_cast(tag), length, ctx.refBuffer().toString()); + + if(length == indefinite_length) + { + Element::run(static_cast(ie), ctx); + + if(ctx) + { + uint8_t const* data_in = ctx.refBuffer().getBytes(2); + if(data_in && (data_in[0] || data_in[1])) + { + ctx.refErrorCtx().errorWrongEndOfContent(); + } + } + } + else + { + if (buffer.getBytesLeft() < length) + { + ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), length); + } + else + { + DecoderCtx::buf_type::pointer end = buffer.end(); + buffer.set_end(buffer.begin() + length); + + Element::run(static_cast(ie), ctx); + + buffer.set_end(end); + } + } + + } + } +}; + +/*************************************************************************************** +* BOOLEAN: Encoding the boolean type (X.690 8.2) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + Length::encode(1, ctx); + if(ie.get()) + Tools::put_bytes(0xFF, 1, ctx); + else + Tools::put_bytes(0, 1, ctx); + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + if(tag_t::value() != tag) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + size_t length = Length::decode(ctx); + if(length != 1) + { + ctx.refErrorCtx().sizeRangeError(length, 1, 1); + } + else + { + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + uint8_t value; + Tools::get_bytes(value, 1, ctx); + ie.set(value > 0); + } + } + } +}; +/*************************************************************************************** +* INTEGER: Encoding the integer type (X.690 8.3) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + size_t length = Length::get(ie.get()); + Length::encode(length, ctx); + Tools::put_bytes(ie.get(), length, ctx); + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + if(tag_t::value() != tag) + { + ctx.refErrorCtx().tagError(static_cast(tag)); + } + else + { + size_t length = Length::decode(ctx); + if(!length || length == indefinite_length) + ctx.refErrorCtx().sizeRangeError(length); + else + { + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + typename IE::value_type value; + Tools::get_bytes(value, length, ctx); + ie.set(value); + } + } + } +}; +/*************************************************************************************** +* ENUMERATED: Encoding the enumerated type (X.690 8.4) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + size_t length = Length::get(ie.get()); + Length::encode(length, ctx); + Tools::put_bytes(ie.get(), length, ctx); + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + if(tag_t::value() != tag) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + size_t length = Length::decode(ctx); + if(!length || length == indefinite_length) + ctx.refErrorCtx().sizeRangeError(length); + else + { + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + typename IE::value_type value; + Tools::get_bytes(value, length, ctx); + ie.set(value); + } + } + } +}; +/*************************************************************************************** +* REAL: Encoding the real type (X.690 8.5) +***************************************************************************************/ +//missing... +/*************************************************************************************** +* BIT STRING: Encoding the bitstring type (X.690 8.6) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + using ctag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value() || tag == ctag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + + uint8_t tail = ie.get_bitqty() % 8; + + size_t length = ie.get_buffer().size(); + Length::encode(length + 1, ctx); + + auto & buffer = ctx.refBuffer(); + buffer.putByte((8 - tail) & 0x7F); + + if (tail) + { + buffer.putBytes(ie.get_buffer().data(), length - 1); + u8 last_byte = *(ie.get_buffer().data() + length - 1); + + last_byte <<= 8 - tail; + buffer.putBytes(&last_byte, 1); + } + else + { + buffer.putBytes(ie.get_buffer().data(), length); + } + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ie.clear(); + if(tag_t::value() == tag) + { + size_t length = Length::decode(ctx); + if(!length || length == indefinite_length) + { + ctx.refErrorCtx().sizeRangeError(length); + } + else + { + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + uint8_t const* data_in = ctx.refBuffer().getBytes(length); + if(data_in) + { + size_t len_bytes = length - 1; + size_t bitqty = len_bytes << 3; + + if((data_in[0] & 0x80) || (bitqty < data_in[0])) + { + ctx.refErrorCtx().valueRangeError(data_in[0]); + } + else + { + bitqty = bitqty - data_in[0]; + uint8_t* data_out = ctx.refAllocator().alloc_bytes(len_bytes); + if (data_out) + { + memcpy(data_out, &data_in[1], len_bytes); + const u8 shift = bitqty % 8; + if (shift) + { + data_out[len_bytes - 1] >>= 8 - shift; + } + ie.set_buffer(bitqty, data_out); + } + else + { + ctx.refErrorCtx().allocatorNoMem(0, len_bytes); + } + } + } + } + } + else if(ctag_t::value() == tag) + { + //todo: implement the segmented data + ctx.refErrorCtx().errorUnsupported(); + } + else + { + ctx.refErrorCtx().tagError(static_cast(tag)); + } + } +}; +/*************************************************************************************** +* OCTET STRING: Encoding the octetstring type (X.690 8.7) +* Restricted Character string types (X.690 8.23) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + using ctag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value() || tag == ctag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + size_t length = ie.get().size(); + Length::encode(length, ctx); + ctx.refBuffer().putBytes(ie.get().data(), length); + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ie.clear(); + if(tag_t::value() == tag) + { + size_t length = Length::decode(ctx); + if(length == indefinite_length) + { + ctx.refErrorCtx().sizeRangeError(length); + } + else + { + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + uint8_t const* data_in = ctx.refBuffer().getBytes(length); + if(data_in) + { + ie.set(length, data_in); + } + } + } + else if(ctag_t::value() == tag) + { + //todo: implement the segmented data + ctx.refErrorCtx().errorUnsupported(); + } + else + { + ctx.refErrorCtx().tagError(static_cast(tag)); + } + } +}; +/*************************************************************************************** +* NULL: Encoding the null type (X.690 8.8) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + Length::encode(0, ctx); + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + if(tag_t::value() != tag) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + size_t length = Length::decode(ctx); + if(length) + ctx.refErrorCtx().sizeRangeError(length); + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + } + } +}; +/*************************************************************************************** +* SEQUENCE: Encoding the sequence type (X.690 8.9) +* SET: Encoding the set type (X.690 8.11) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + auto & buffer = ctx.refBuffer(); + + tag_t::encode(ctx); + u8* len_ptr = buffer.advance(1); //reserve for the length + + VisitorEncoderSeq ve(ctx, ie); + ie.encode(ve); + + size_t len = buffer.begin() - len_ptr - 1; + if(len > 127) + { + len_ptr[0] = 0x80; //undefinite length form per X.690 8.1.3.6 + uint8_t buff[2] = {0}; // end-of-contents octets (X.690 8.1.5) + buffer.putBytes(buff, sizeof(buff)); + } + else + len_ptr[0] = static_cast(len); //one byte form per X.690 8.1.3.4 + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) //todo: support arbitrary order of IEs in SET + { + if(tag_t::value() != tag) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + VisitorDecoderSeq vd(ctx, ie); + auto & buffer = ctx.refBuffer(); + + size_t length = Length::decode(ctx); + + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + + if(length == indefinite_length) + { + ie.decode(vd); + if(ctx) + { + if(invalid_tag != vd.get_unhandled_tag()) + { + tag_value_t _tag = vd.get_unhandled_tag(); + if(IE::constraint_t::extended) //skip the unknown extension now + { + tag_value_t const* tag_ptr = &_tag; + size_t _length; + do + { + _tag = OpenType::decode(ctx, _length, tag_ptr); + tag_ptr = nullptr; + + } while(ctx && !(_tag == 0 && _length == 0)); + } + else // it should be the end-of-contents octets (8.1.5) + { + uint8_t const* data_in = ctx.refBuffer().getBytes(1); + if(data_in && (_tag || data_in[0])) + { + ctx.refErrorCtx().errorWrongEndOfContent(); + } + } + } + else + { + uint8_t const* data_in = ctx.refBuffer().getBytes(2); + if(data_in && (data_in[0] || data_in[1])) + { + ctx.refErrorCtx().errorWrongEndOfContent(); + } + } + } + } + else + { + if (buffer.getBytesLeft() < length) + { + ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), length); + } + else + { + DecoderCtx::buf_type::pointer end = buffer.end(); + buffer.set_end(buffer.begin() + length); + ie.decode(vd); + tag_value_t _tag = vd.get_unhandled_tag(); + if(invalid_tag != _tag) + { + if(IE::constraint_t::extended) //skip the unknown extension now + { + tag_value_t const* tag_ptr = &_tag; + size_t _length; + do + { + _tag = OpenType::decode(ctx, _length, tag_ptr); + tag_ptr = nullptr; + + } while(ctx && buffer.getBytesLeft() > 0); + } + else + ctx.refErrorCtx().tagError(static_cast(tag)); // unexpected tag + } + buffer.set_end(end); + } + } + + } + } +}; +/*************************************************************************************** +* SEQUENCE OF: Encoding the sequence-of type (X.690 8.10) +* SET OF: Encoding the set-of type (X.690 8.12) +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t tag) {return tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + auto & buffer = ctx.refBuffer(); + + tag_t::encode(ctx); + u8* len_ptr = buffer.advance(1); //reserve for the length + + for (auto& elem : ie) + { + Element::run(elem, ctx); + } + + size_t len = buffer.begin() - len_ptr - 1; + if(len > 127) + { + len_ptr[0] = 0x80; //undefinite length form per X.690 8.1.3.6 + uint8_t buff[2] = {0}; // end-of-contents octets (X.690 8.1.5) + buffer.putBytes(buff, sizeof(buff)); + } + else + len_ptr[0] = static_cast(len); //one byte form per X.690 8.1.3.4 + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ie.clear(); + + if(tag_t::value() != tag) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + auto & buffer = ctx.refBuffer(); + + size_t length = Length::decode(ctx); + + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + + if(length == indefinite_length) + { + tag_value_t elm_tag = get_tag(ctx); + + while(ctx && Element::is_matched(elm_tag)) + { + add_element(ie, ctx, &elm_tag); + elm_tag = get_tag(ctx); + } + + if(ctx) + { + uint8_t const* data_in = ctx.refBuffer().getBytes(1); + if(data_in && (elm_tag || data_in[0])) + { + ctx.refErrorCtx().errorWrongEndOfContent(); + } + } + } + else + { + if (buffer.getBytesLeft() < length) + { + ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), length); + } + else + { + DecoderCtx::buf_type::pointer end = buffer.end(); + buffer.set_end(buffer.begin() + length); + + while(ctx && buffer.getBytesLeft() > 0) + add_element(ie, ctx); + + buffer.set_end(end); + } + } + } + } + +private: + static void inline add_element(IE& ie, DecoderCtx& ctx, tag_value_t const* elm_tag = nullptr) + { + uint8_t* data = ctx.refAllocator().alloc_bytes(sizeof(typename IE::value_type)); + if (data) + { + typename IE::value_type * v = new (data) typename IE::value_type; + v->clear(); + ie.push_back(*v); + Element::run(*v, ctx, elm_tag); + } + else + { + ctx.refErrorCtx().allocatorNoMem(0, sizeof(typename IE::value_type)); + } + } +}; + +/*************************************************************************************** +* CHOICE: Encoding the choice type +***************************************************************************************/ +struct ChoiceVisitorEncoder +{ + ChoiceVisitorEncoder(EncoderCtx& ctx) : m_ctx(ctx) {} + + template + bool operator()(IE const& ie) + { + Element::run(ie, m_ctx); + return static_cast(m_ctx); + } + + EncoderCtx& m_ctx; +}; + +struct ChoiceVisitorDecoder +{ + ChoiceVisitorDecoder(DecoderCtx& ctx, tag_value_t tag) : m_ctx(ctx), m_tag(tag) {} + + template bool operator()(IE& ie) + { + Element::run(ie, m_ctx, &m_tag); + return static_cast(m_ctx); + } + + DecoderCtx& m_ctx; + tag_value_t m_tag; +}; + +template +struct ElementType > +{ + struct Selector + { + Selector(tag_value_t tag) : m_tag(tag) {} + + template void operator()(size_t idx) + { + if(!m_valid && Element::is_matched(m_tag)) + { + m_index = idx; + m_valid = true; + } + } + + size_t get_idx() const {return m_index;} + bool is_valid() const {return m_valid;} + + private: + tag_value_t m_tag; + size_t m_index {0}; + bool m_valid {false}; + }; + + static bool inline is_matched(tag_value_t tag) + { + Selector selector {tag}; + IE::enumerate(selector); + return selector.is_valid(); + } + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + ChoiceVisitorEncoder ve(ctx); + + if(ctx && !ie.encode(ve)) + ctx.refErrorCtx().tagError(ie.get_index()); + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ie.clear(); + + Selector selector {tag}; + IE::enumerate(selector); + + if(!selector.is_valid()) + ctx.refErrorCtx().tagError(static_cast(tag)); + else + { + ChoiceVisitorDecoder vd {ctx, tag}; + if(ctx && !ie.decode(selector.get_idx(), vd)) + ctx.refErrorCtx().tagError(ie.get_index()); + } + } +}; + +template +struct ElementType > +{ + static bool inline is_matched(tag_value_t _tag) {return ExplicitCodec::is_matched(_tag);} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + ExplicitCodec::run(ie, ctx); + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ExplicitCodec::run(ie, ctx, tag); + } +}; + +/*************************************************************************************** +* IE_OBJECT_IDENTIFIER: Encoding the object identifier type +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t _tag) {return _tag == tag_t::value();} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + tag_t::encode(ctx); + size_t length = ie.get().size(); + Length::encode(length, ctx); + ctx.refBuffer().putBytes(ie.get().data(), length); + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ie.clear(); + if(tag_t::value() == tag) + { + size_t length = Length::decode(ctx); + if(!length || length == indefinite_length) + { + ctx.refErrorCtx().sizeRangeError(length); + } + else + { + ASN_DECODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), static_cast(tag), length, ctx.refBuffer().toString()); + uint8_t const* data_in = ctx.refBuffer().getBytes(length); + if(data_in) + { + ie.set(length, data_in); + } + } + } + else + { + ctx.refErrorCtx().tagError(static_cast(tag)); + } + } +}; + +/*************************************************************************************** +* T_OBJFIELD_FTV +***************************************************************************************/ +template +struct ElementType > +{ + using tag_t = Tag; + + static bool inline is_matched(tag_value_t _tag) {return _tag == tag_t::value();} +}; + +/*************************************************************************************** +* T_OBJFIELD_TF +***************************************************************************************/ +template +struct ElementType > +{ + struct Selector + { + Selector(tag_value_t tag) : m_tag(tag) {} + + template void operator()(size_t idx) + { + if(Element::is_matched(m_tag)) + { + m_index = idx; + m_valid = true; + } + } + + size_t get_idx() const {return m_index;} + bool is_valid() const {return m_valid;} + + private: + tag_value_t m_tag; + size_t m_index {0}; + bool m_valid {false}; + }; + + static bool inline is_matched(tag_value_t tag) + { + Selector selector(tag); + IE::enumerate(selector); + + return selector.is_valid(); + } +}; + +/*************************************************************************************** +* Identifier +***************************************************************************************/ +template +struct Identifier +{ + static bool inline is_matched(tag_value_t _tag) + { + return ElementType::is_matched(_tag); + } + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + ElementType::run(ie, ctx); + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ElementType::run(ie, ctx, tag); + } +}; + +template +struct Identifier > +{ + static bool inline is_matched(tag_value_t _tag) {return ExplicitCodec::is_matched(_tag);} + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + ExplicitCodec::run(ie, ctx); + } + + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t tag) + { + ExplicitCodec::run(ie, ctx, tag); + } +}; + +/*************************************************************************************** +* COMMON: Element +***************************************************************************************/ +template +struct Element +{ + static bool inline is_matched(tag_value_t _tag) + { + return Identifier::is_matched(_tag); + } + + static void inline run(IE const& ie, EncoderCtx& ctx) + { + if (ctx) + { + ASN_ENCODER_TRACE("IE buffer: %s", static_cast(IE::ie_type), IE::name(), ctx.refBuffer().toString()); + ctx.ie_name(IE::name()); + Identifier::run(ie, ctx); + } + } + static void inline run(IE& ie, DecoderCtx& ctx, tag_value_t const* tag_ptr = nullptr) + { + if (ctx) + { + ctx.ie_name(IE::name()); + + tag_value_t tag = tag_ptr ? *tag_ptr : get_tag(ctx); + if(ctx) + Identifier::run(ie, ctx, tag); + } + } +}; + +} //namespace ber +} //namespace asn