--- /dev/null
+#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
+#include <boost/intrusive/list.hpp>
+#include <cstring>
+
+// Local Includes: Application specific classes, functions, and libraries
+#include "asn/constraints.hpp"
+#include "asn/identifier.hpp"
+
+namespace asn {
+
+enum class element_type : uint8_t
+{
+ T_BOOLEAN
+ ,T_INTEGER
+ ,T_ENUMERATED
+ ,T_REAL
+ ,T_BITSTRING
+ ,T_OCTETSTRING
+ ,T_NULL
+ ,T_SEQUENCE
+ ,T_SEQUENCE_OF
+ ,T_SET
+ ,T_SET_OF
+ ,T_CHOICE
+ ,T_OBJECTIDENTIFIER
+ ,T_OBJFIELD_FTV
+ ,T_OBJFIELD_TF
+};
+
+/***************************************************************************************
+* BASE
+***************************************************************************************/
+
+struct base
+{
+ static constexpr bool optional = false;
+ static constexpr bool extension = false;
+
+ static constexpr char const* name() {return "";}
+
+ void setpresent(bool p) {is_set = p;}
+ void clear() {is_set = false;}
+
+ bool is_valid() const {return is_set;}
+
+protected:
+ base() {}
+ void set() {is_set = true;}
+protected:
+ bool is_set {false};
+
+ base& operator=(const base&) = delete;
+ base (const base&) = delete;
+};
+
+/***************************************************************************************
+* IE_NULL
+***************************************************************************************/
+
+struct nulltype : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::NULL_TYPE), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_NULL;
+ static constexpr const char* name() {return "NULL";}
+
+ void clear() {}
+};
+
+/***************************************************************************************
+* T_BOOLEAN
+***************************************************************************************/
+
+struct boolean : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::BOOLEAN), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_BOOLEAN;
+ static constexpr const char* name() {return "BOOLEAN";}
+
+ using value_type = bool;
+
+ void set(value_type vl) { m_value = vl; base::set();}
+ value_type get() const { return m_value; }
+ void clear() { m_value = false; base::clear();}
+
+private:
+ value_type m_value {false};
+};
+
+/***************************************************************************************
+* T_INTEGER
+***************************************************************************************/
+template < class Constraint = constraints<false> >
+struct integer : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::INTEGER), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_INTEGER;
+ static constexpr const char* name() {return "INTEGER";}
+
+ using constraint_t = Constraint;
+ using value_type = int64_t;
+
+ bool equal(value_type v) const {return m_value == v;}
+
+ void set(value_type v) { m_value = v; base::set();}
+ value_type get() const { return m_value; }
+
+ void clear() { m_value = 0; base::clear();}
+
+private:
+ value_type m_value;
+};
+
+/***************************************************************************************
+* T_ENUMERATED
+***************************************************************************************/
+template<int TotalNumEntries, int NumExtEntries, bool Extended>
+struct enumerated : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::ENUMERATED), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_ENUMERATED;
+ static constexpr const char* name() {return "ENUMERATED";}
+
+ using constraint_t = seq_range<TotalNumEntries, NumExtEntries, Extended>;
+ using value_type = typename constraint_t::value_type;
+
+ bool equal(value_type v) const {return m_value == v;}
+ void set(value_type vl) { m_value = vl; base::set();}
+ value_type get() const { return m_value; }
+ void clear() { m_value = constraint_t::default_value; base::clear();}
+
+private:
+ value_type m_value;
+};
+
+/***************************************************************************************
+* T_OCTETSTRING
+***************************************************************************************/
+template< class Constraint = constraints<false> >
+struct ostring : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::OCTET_STRING), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_OCTETSTRING;
+ static constexpr const char* name() {return "OCTET STING";}
+ using constraint_t = Constraint;
+
+ struct value_type
+ {
+ value_type() {}
+ value_type(size_t size, const char* data) : m_size(size), m_data(reinterpret_cast<const uint8_t*>(data)) {}
+
+ size_t size() const { return m_size; }
+ const uint8_t* data() const { return m_data; }
+
+ using const_iterator = uint8_t const*;
+ const_iterator begin() const { return data(); }
+ const_iterator end() const { return begin() + size(); }
+
+ void assign(void const* p, size_t sz) { m_data = static_cast<uint8_t const*>(p); m_size = sz; }
+
+ private:
+ const uint8_t* m_data{ 0 };
+ size_t m_size{ 0 };
+ };
+
+ value_type const& get() const { return m_value; }
+
+ //Use std::string, std::vector or IE_OSTR::value_type
+ template<typename T> value_type const& set(T const& tval)
+ {
+ set(tval.size(), tval.data());
+ base::set();
+ return m_value;
+ }
+
+ void set(size_t size, void const* data)
+ {
+ m_value.assign(data, size);
+ base::set();
+ }
+
+ template<class AT>
+ ostring& emplace(AT& allocator, size_t size, uint8_t const * data_in)
+ {
+ if(size)
+ {
+ base::clear();
+ uint8_t* data_out = allocator.alloc_bytes(size);
+ if (data_out)
+ {
+ memcpy(data_out, data_in, size);
+ set(size, data_out);
+ }
+ }
+ else
+ base::set();
+ return *this;
+ }
+
+ template<class AT, class T>
+ ostring& emplace(AT& allocator, T const& tval)
+ {
+ return emplace(allocator, tval.size(), reinterpret_cast<const uint8_t*>(tval.data()));
+ }
+
+ void clear() { m_value = value_type{}; base::clear();}
+
+private:
+ value_type m_value;
+};
+
+/***************************************************************************************
+* T_BITSTRING
+***************************************************************************************/
+template<class Constraint = constraints<false> >
+struct bstring : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::BIT_STRING), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_BITSTRING;
+ static constexpr const char* name() {return "BIT STING";}
+ using constraint_t = Constraint;
+
+ struct value_type
+ {
+ value_type() {}
+ value_type(size_t size, const char* data, size_t bitqty) : m_size(size), m_data(reinterpret_cast<const uint8_t*>(data)), m_bitqty(bitqty){}
+
+ size_t size() const { return m_size; }
+ const uint8_t* data() const { return m_data; }
+ size_t bitqty() const { return m_bitqty; }
+
+ void assign(void const* p, size_t sz, size_t bits) { m_data = static_cast<uint8_t const*>(p); m_size = sz; m_bitqty = bits; }
+
+ private:
+ const uint8_t* m_data{ nullptr };
+ size_t m_size{ 0 };
+ size_t m_bitqty{ 0 };
+ };
+
+ value_type const& get_buffer() const { return m_value; }
+
+ size_t get_bitqty() const { return m_value.bitqty(); }
+
+ //Use std::string, std::vector or IE_BSTR::value_type
+ template<typename T> value_type const& set_buffer(T& tval, size_t bitqty)
+ {
+ m_value.assign(tval.data(), tval.size(), bitqty);
+ base::set();
+ return m_value;
+ }
+
+ void set_buffer(size_t bitqty, const uint8_t* data)
+ {
+ m_value.assign(data, (bitqty +7) >> 3, bitqty);
+ base::set();
+ }
+
+ template<class AT>
+ bstring& emplace_buffer(AT& allocator, size_t bitqty, uint8_t const * data_in)
+ {
+ size_t size = (bitqty +7) >> 3;
+ uint8_t* data_out = allocator.alloc_bytes(size);
+ if (!data_out) {
+ throw std::bad_alloc();
+ }
+ memcpy(data_out, data_in, size);
+ set_buffer(bitqty, data_out);
+ return *this;
+ }
+
+ void clear() { m_value = value_type{}; base::clear();}
+
+ uint64_t get_number() const
+ {
+ uint64_t retval{0};
+ size_t i = 0;
+ for(; i < m_value.size() - 1; ++i)
+ {
+ retval <<= 8;
+ retval |= m_value.data()[i];
+ }
+
+ uint8_t shift = m_value.bitqty() % 8;
+ if (shift)
+ {
+ retval <<= shift;
+ }
+ else
+ {
+ retval <<= 8;
+ }
+
+ retval |= m_value.data()[i];
+
+ return retval;
+ }
+
+ template<class AT>
+ void set_number(AT& allocator, size_t bitqty, uint64_t data)
+ {
+ size_t size = (bitqty +7) >> 3;
+ uint8_t* data_out = allocator.alloc_bytes(size);
+ if (!data_out) {
+ throw std::bad_alloc();
+ }
+
+ const uint8_t shift = bitqty % 8;
+ if (shift)
+ {
+ data_out[size-1] = data & (0xFF >> (8 - shift));
+ data >>= shift;
+ }
+ else
+ {
+ data_out[size-1] = data & (0xFF);
+ data >>= 8;
+ }
+
+ for (size_t i = 1; i <= size - 1; i++)
+ {
+ data_out[size-1-i] = data & (0xFF);
+ data >>= 8;
+ }
+
+ m_value.assign(data_out, size, bitqty);
+ base::set();
+ }
+
+private:
+ value_type m_value;
+};
+
+/***************************************************************************************
+* T_CHOICE
+***************************************************************************************/
+template<int TotalNumEntries, int NumExtEntries, bool Extended>
+struct choice : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNSPECIFIED, static_cast<tag_value_t>(tag_rvalue_t::CHOICE), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_CHOICE;
+ static constexpr const char* name() {return "CHOICE";}
+
+ using constraint_t = seq_range<TotalNumEntries, NumExtEntries, Extended>;
+ using index_type = size_t;
+ using value_type = size_t;
+
+ static constexpr index_type fst_index = 1;
+ static constexpr index_type ext_index = fst_index + TotalNumEntries;
+
+ static index_type normalize(index_type idx) {return idx - fst_index;}
+ static index_type denormalize(index_type idx) {return idx + fst_index;}
+};
+
+/***************************************************************************************
+* T_SEQUENCE
+***************************************************************************************/
+template<int TotalNumEntries, int NumExtEntries, bool Extended, int NumOptEntries = 0>
+struct sequence : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::SEQUENCE), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_SEQUENCE;
+ static constexpr const char* name() {return "SEQUENCE";}
+
+ static constexpr bound_t num_total_entries = TotalNumEntries;
+ static constexpr bound_t num_opt_entries = NumOptEntries;
+ static constexpr bound_t num_ext_entries = NumExtEntries;
+
+ using constraint_t = seq_range<TotalNumEntries, NumExtEntries, Extended>;
+
+};
+
+/***************************************************************************************
+* T_SEQUENCE_OF
+***************************************************************************************/
+template<typename T, class Constraint = constraints<false> >
+struct sequenceof : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::SEQUENCE_OF), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_SEQUENCE_OF;
+ static constexpr const char* name() {return "SEQUENCE OF";}
+
+ struct value_type : T, boost::intrusive::list_base_hook< boost::intrusive::link_mode<boost::intrusive::auto_unlink> >
+ {
+ value_type(){}
+ private:
+ value_type& operator=(const value_type&) = delete;
+ value_type (const value_type&) = delete;
+ };
+
+ using values_t = boost::intrusive::list<value_type, boost::intrusive::constant_time_size<false>>;
+ using constraint_t = Constraint;
+ using element_t = T;
+
+ void clear() { m_list.clear(); base::clear();}
+ size_t size() const { return m_list.size(); }
+ template<class Predicate>
+ void sort(Predicate const& p) { m_list.sort(p); }
+
+ template<class V>
+ void set(V& v) {for(auto & e : v) {m_list.push_back(e);} base::set();}
+
+ void push_back(value_type& v) { m_list.push_back(v); base::set();}
+
+ template<class AT> //Note: Allocator must return word alligned buffer!
+ T& emplace_back(AT& allocator)
+ {
+ uint8_t* data = allocator.alloc_bytes(sizeof(value_type));
+ if(!data)
+ throw std::bad_alloc();
+ value_type* v = new (data) value_type;
+ push_back(*v);
+ return *v;
+ };
+
+ using iterator = typename values_t::iterator;
+ iterator begin() { return m_list.begin(); }
+ iterator end() { return m_list.end(); }
+
+ using const_iterator = typename values_t::const_iterator;
+ const_iterator begin() const { return m_list.begin(); }
+ const_iterator end() const { return m_list.end(); }
+
+ sequenceof(){}
+
+private:
+ values_t m_list;
+};
+
+/***************************************************************************************
+* T_OBJFIELD_FTV
+***************************************************************************************/
+template<typename T, bool>
+struct fixedtypefield : T
+{
+ static constexpr element_type ie_type = element_type::T_OBJFIELD_FTV;
+
+ T& ref_nested() {return *this;}
+ T const & ref_nested() const {return *this;}
+};
+
+/***************************************************************************************
+* T_OBJFIELD_TF
+***************************************************************************************/
+template<bool>
+struct typefield : base
+{
+ static constexpr element_type ie_type = element_type::T_OBJFIELD_TF;
+ static constexpr const char* name() {return "type-field";}
+
+ typefield& ref_nested() {return *this;}
+ typefield const& ref_nested() const {return *this;}
+
+ bool is_unknown() const {return false;}
+};
+
+/***************************************************************************************
+* T_OBJECTIDENTIFIER
+***************************************************************************************/
+struct oid : ostring<>
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::OBJECT_IDENTIFIER), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_OBJECTIDENTIFIER;
+ static constexpr const char* name() {return "OBJECT IDENTIFIER";}
+};
+
+/***************************************************************************************
+* T_PRINTABLESTRING
+***************************************************************************************/
+template<class Constraint = constraints<false> >
+struct printable_string : ostring<Constraint>
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::PrintableString), tag_type_t::IMPLICIT>;
+ static constexpr const char* name() {return "PrintableString";}
+};
+
+/***************************************************************************************
+* T_IA5_STRING
+***************************************************************************************/
+template<class Constraint = constraints<false> >
+struct ia5_string : ostring<Constraint>
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::IA5String), tag_type_t::IMPLICIT>;
+ static constexpr const char* name() {return "IA5String";}
+};
+
+/***************************************************************************************
+* T_GRAPHIC_STRING
+***************************************************************************************/
+template<class Constraint = asn::constraints<false> >
+struct graphic_string : ostring<Constraint>
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::GraphicString), tag_type_t::IMPLICIT>;
+ static constexpr const char* name() {return "IA5String";}
+};
+
+/***************************************************************************************
+* T_UTF8_STRING
+***************************************************************************************/
+template<class Constraint = asn::constraints<false> >
+struct utf8_string : ostring<Constraint>
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::UTF8String), tag_type_t::IMPLICIT>;
+ static constexpr const char* name() {return "UTF8String";}
+};
+
+/***************************************************************************************
+* T_SET
+***************************************************************************************/
+template<int TotalNumEntries, int NumExtEntries, bool Extended, int NumOptEntries = 0>
+struct set : base
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::SET), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_SET;
+ static constexpr const char* name() {return "SET";}
+
+ static constexpr bound_t num_total_entries = TotalNumEntries;
+ static constexpr bound_t num_opt_entries = NumOptEntries;
+ static constexpr bound_t num_ext_entries = NumExtEntries;
+
+ using constraint_t = seq_range<TotalNumEntries, NumExtEntries, Extended>;
+};
+
+/***************************************************************************************
+* T_SET_OF
+***************************************************************************************/
+template<typename T, class Constraint = constraints<false> >
+struct setof : sequenceof<T, Constraint>
+{
+ using asn_identifier_t = identifier<class_type_t::UNIVERSAL, static_cast<tag_value_t>(tag_rvalue_t::SET_OF), tag_type_t::IMPLICIT>;
+
+ static constexpr element_type ie_type = element_type::T_SET_OF;
+ static constexpr const char* name() {return "SET OF";}
+};
+} //namespace asn