#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/per/common.hpp" #include "asn/per/visitor.hpp" namespace asn { namespace per { /****************************************************************** * Adapter *****************************************************************/ template struct Adapter { static void inline run(IE const& ie, EncoderCtx& ctx, Container const& cont) { Element::run(ie, ctx); } static void inline run(IE& ie, DecoderCtx& ctx, Container const& cont) { Element::run(ie, ctx); } }; template struct Adapter> { static void inline run(IE const& ie, EncoderCtx& ctx, Container const& cont) { VisitorEncoder v(ctx); bool rv = ie.encode(v, cont); if(!rv && static_cast(ctx)) { ctx.refErrorCtx().errorNoObject(Container::name()); } } static void inline run(IE& ie, DecoderCtx& ctx, Container const& cont) { VisitorDecoder v(ctx); bool rv = ie.decode(v, cont); if(!rv && static_cast(ctx)) { ctx.refErrorCtx().errorNoObject(Container::name()); } } }; template struct Adapter > { static void inline run(IE const& ie, EncoderCtx& ctx, Container const& cont) { OpenTypeVisitorEncoder v(ctx); bool rv = ie.encode(v, cont); if(!rv && static_cast(ctx)) { ctx.refErrorCtx().errorNoObject(Container::name()); } } static void inline run(IE& ie, DecoderCtx& ctx, Container const& cont) { OpenTypeVisitorDecoder v(ctx); bool rv = ie.decode(v, cont); if(!rv && static_cast(ctx)) { ctx.refErrorCtx().errorNoObject(Container::name()); } if(ie.is_unknown()) //skip the unknown Open Type { size_t size = LengthDeterminantDefault::run(ctx); DecoderCtx::buf_type& buffer = ctx.refBuffer(); if (buffer.getBytesLeft() < size) ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), size); else buffer.advance(size); } } }; /****************************************************************** * RootEncoder *****************************************************************/ template struct RootEncoder { RootEncoder(EncoderCtx& ctx, Container const& cont) : m_ctx(ctx), m_cont(cont) {} template bool operator() (IE const& ie) const { if(!IE::extension) { if(IE::optional && !ie.is_valid()) return static_cast(m_ctx); Adapter::run(ie, m_ctx, m_cont); } return static_cast(m_ctx); } EncoderCtx& m_ctx; Container const& m_cont; }; /****************************************************************** * RootDecoder *****************************************************************/ template struct RootDecoder { RootDecoder(DecoderCtx& ctx, Container const& cont) : m_ctx(ctx), m_cont(cont) {} template bool operator() (IE& ie) const { if(!IE::extension) { if(IE::optional) { if(m_ctx.map_elm()) { ie.setpresent(true); Adapter::run(ie, m_ctx, m_cont); } else ie.setpresent(false); } else { Adapter::run(ie, m_ctx, m_cont); } } return static_cast(m_ctx); } DecoderCtx& m_ctx; Container const& m_cont; }; /****************************************************************** * ExtEncoder *****************************************************************/ template struct ExtEncoder { explicit ExtEncoder(EncoderCtx& ctx, Container const& cont) : m_ctx(ctx), m_cont(cont) {} template bool operator() (IE const& ie) const { if(!IE::extension) return static_cast(m_ctx); if(IE::optional && !ie.is_valid()) return static_cast(m_ctx); size_t reserved_size = 1; //1 byte length is most likely Tools::bit_accessor::padByte(m_ctx.refBuffer()); if (m_ctx.refBuffer().getBytesLeft()) { EncoderCtx::buf_type::pointer p = m_ctx.refBuffer().advance(reserved_size); EncoderCtx::buf_type::pointer start = p + reserved_size; Adapter::run(ie, m_ctx, m_cont); if (m_ctx) { Tools::bit_accessor::padByte(m_ctx.refBuffer()); EncoderCtx::buf_type::pointer p_new = m_ctx.refBuffer().begin(); size_t size = p_new - start; size_t needed = LengthDeterminantDefault::bytes_needed(size) - reserved_size; if (needed) //1 byte is not enough for the length determinant. it is hardly possible { if (m_ctx.refBuffer().getBytesLeft() < needed) { m_ctx.refErrorCtx().lengthErrorBytes(m_ctx.refBuffer().getBytesLeft(), needed); return false; } memmove(start + needed, start, size); p_new += needed; } m_ctx.refBuffer().set_begin(p, 0); LengthDeterminantDefault::run(m_ctx, size); if (m_ctx) { m_ctx.refBuffer().set_begin(p_new, 0); Tools::bit_accessor::padByte(m_ctx.refBuffer()); } } } else { m_ctx.refErrorCtx().lengthErrorBytes(m_ctx.refBuffer().getBytesLeft(), reserved_size); return false; } return static_cast(m_ctx); } EncoderCtx& m_ctx; Container const& m_cont; }; /****************************************************************** * ExtDecoder *****************************************************************/ template struct ExtDecoder { explicit ExtDecoder(DecoderCtx& ctx, Container const& cont) : m_ctx(ctx), m_cont(cont) {} template bool operator() (IE& ie) const { if(!IE::extension) return static_cast(m_ctx); if (m_ctx.map_elm()) { ie.setpresent(true); size_t size = LengthDeterminantDefault::run(m_ctx); DecoderCtx::buf_type& buffer = m_ctx.refBuffer(); if (buffer.getBytesLeft() < size) { m_ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), size); return false; } DecoderCtx::buf_type::pointer end = buffer.end(); buffer.set_end(buffer.begin() + size); Adapter::run(ie, m_ctx, m_cont); Tools::bit_accessor::padByte(m_ctx.refBuffer()); buffer.set_end(end); } else { ie.setpresent(false); } return static_cast(m_ctx); } DecoderCtx& m_ctx; Container const& m_cont; }; /****************************************************************** * SeqMap *****************************************************************/ template struct SeqMap; /* template struct SeqMap 8) > > { static void inline run(EncoderCtx& ctx, size_t val) { u8 k = IE::num_opt_entries / 8; // num of full bytes in a seq map mask u8 fb_bits = IE::num_opt_entries % 8; // num of first byte bits (without padding) if (fb_bits) { // Put a part of a first byte (without padding, only seq map own bits) Tools::bit_accessor::put((u8)(val >> 8*k), fb_bits, ctx.refBuffer()); } // Put other bytes (full bytes) for (int i = (k-1); i >= 0; i--) { Tools::bit_accessor::put((u8)(val >> 8*i), 8, ctx.refBuffer()); } } static DecoderCtx::map_type inline run(DecoderCtx& ctx) { uint num_opts = IE::num_opt_entries; u64 res = 0; u8 k = 1; u8 lb_bits = IE::num_opt_entries % 8; // num of last byte bits (without padding) while (num_opts >= 8) { size_t shift = sizeof(DecoderCtx::map_type) * CHAR_BIT - 8*k; DecoderCtx::map_type rval = Tools::bit_accessor::get(8, ctx.refBuffer()); rval = rval << shift; res |= rval; k++; num_opts -= 8; } if (lb_bits > 0) { // (8 - lb_bits) - padding in a last byte size_t shift = sizeof(DecoderCtx::map_type) * CHAR_BIT - 8*k + 8 - lb_bits; DecoderCtx::map_type rval = Tools::bit_accessor::get(lb_bits, ctx.refBuffer()); rval = rval << shift; res |= rval; } return res; } } ; */ template struct SeqMap > //todo: to add code for more than 8 optional elements { static void inline run(EncoderCtx& ctx, size_t val) { Tools::bit_accessor::put((u8)val, IE::num_opt_entries, ctx.refBuffer()); } static DecoderCtx::map_type inline run(DecoderCtx& ctx) { size_t shift = sizeof(DecoderCtx::map_type) * CHAR_BIT - IE::num_opt_entries; DecoderCtx::map_type rval = Tools::bit_accessor::get(IE::num_opt_entries, ctx.refBuffer()); rval = rval << shift; return rval; } }; /****************************************************************** * SeqExtMap *****************************************************************/ template struct SeqExtMap { static void inline run(EncoderCtx& ctx, size_t val) {} static DecoderCtx::map_type inline run(DecoderCtx& ctx) { size_t len = NormallySmallLength<1>::run(ctx); size_t shift = sizeof(DecoderCtx::map_type) * CHAR_BIT - len; u8 tmp; DecoderCtx::map_type rval{ 0 }; u8 val; while (len) { tmp = len > 8 ? 8 : (u8)len; val = Tools::bit_accessor::get(tmp, ctx.refBuffer()); rval = rval << tmp; rval |= val; len -= tmp; } rval = rval << shift; return rval; } }; template struct SeqExtMap 0)) > > { static void inline run(EncoderCtx& ctx, size_t val) { NormallySmallLength::run(ctx); Tools::bit_accessor::put((u8)val, NumExtEntries, ctx.refBuffer()); } }; template struct SeqExtMap 8) > > { static void inline run(EncoderCtx& ctx, size_t val) { NormallySmallLength::run(ctx); size_t len = NumExtEntries; size_t tmp; while (len) { tmp = len > 8 ? 8 : len; Tools::bit_accessor::put((u8)val, tmp, ctx.refBuffer()); val = val >> tmp; len -= tmp; } } }; /****************************************************************** * SeqMapBuilder *****************************************************************/ struct SeqMapBuilder { SeqMapBuilder(uint64_t& map) : m_map(map) {} template bool operator()(IE const& ie) { if(!IE::extension && IE::optional) { m_map = m_map << 1; if(ie.is_valid()) m_map |= 1; } return true; } uint64_t& m_map; }; /****************************************************************** * SeqExtMapBuilder *****************************************************************/ struct SeqExtMapBuilder { SeqExtMapBuilder(uint64_t& map) : m_map(map) {} template bool operator()(IE const& ie) { if(IE::extension) { m_map = m_map << 1; if(!IE::optional || (IE::optional && ie.is_valid())) m_map |= 1; } return true; } uint64_t& m_map; }; /****************************************************************** * SeqNoExtDefault *****************************************************************/ // Default (No OPT/DEF present within the extension root) template struct SeqNoExtDefault { static void inline run(IE const& ie, EncoderCtx& ctx) { RootEncoder ve(ctx, ie); ie.encode(ve); } static void inline run(IE& ie, DecoderCtx& ctx, DecoderCtx::map_type map = 0) { RootDecoder ve(ctx, ie); DecoderCtx::map_type old_map = ctx.set_map(map); ie.decode(ve); ctx.set_map(old_map); } }; /****************************************************************** * SeqNoExt *****************************************************************/ // Default (No OPT/DEF present within the extension root) template struct SeqNoExt { static void inline run(IE const& ie, EncoderCtx& ctx) { SeqNoExtDefault::run(ie, ctx); } static void inline run(IE& ie, DecoderCtx& ctx) { SeqNoExtDefault::run(ie, ctx); } }; //18.2 OPT/DEF present within the extension root template struct SeqNoExt 0) > > { static void inline run(IE const& ie, EncoderCtx& ctx) { uint64_t map = 0; SeqMapBuilder mb(map); ie.encode(mb); SeqMap::run(ctx, map); SeqNoExtDefault::run(ie, ctx); } static void inline run(IE& ie, DecoderCtx& ctx) { SeqNoExtDefault::run(ie, ctx, SeqMap::run(ctx)); } }; /****************************************************************** * Seq *****************************************************************/ template struct Seq; template struct Seq > { static void inline run(IE const& ie, EncoderCtx& ctx) { uint64_t map = 0; SeqExtMapBuilder emb(map); ie.encode(emb); if (map) { Tools::bit_accessor::put(1, 1, ctx.refBuffer()); SeqNoExt::run(ie, ctx); SeqExtMap::run(ctx, map); ExtEncoder ove(ctx, ie); ie.encode(ove); } else { Tools::bit_accessor::put(0, 1, ctx.refBuffer()); SeqNoExt::run(ie, ctx); } } static void inline run(IE& ie, DecoderCtx& ctx) { u8 ext = Tools::bit_accessor::get(1, ctx.refBuffer()); if (ext) { SeqNoExt::run(ie, ctx); auto old_map = ctx.set_map(SeqExtMap::run(ctx)); // we do not know how many exts can be received { ExtDecoder ove(ctx, ie); ie.decode(ove); auto& buffer = ctx.refBuffer(); while(ctx.get_map()) { if(ctx.map_elm()) //skip unknown extensions { size_t size = LengthDeterminantDefault::run(ctx); if (buffer.getBytesLeft() < size) { ctx.refErrorCtx().lengthErrorBytes(buffer.getBytesLeft(), size); break; } buffer.advance(size); } } } ctx.set_map(old_map); } else SeqNoExt::run(ie, ctx); } }; template struct Seq > { static void inline run(IE const& ie, EncoderCtx& ctx) { SeqNoExt::run(ie, ctx); } static void inline run(IE& ie, DecoderCtx& ctx) { SeqNoExt::run(ie, ctx); } }; } //namespace per } //namespace asn