#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 #include // 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(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(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 > struct integer : base { using asn_identifier_t = identifier(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 struct enumerated : base { using asn_identifier_t = identifier(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; 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 > struct ostring : base { using asn_identifier_t = identifier(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(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(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 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 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 ostring& emplace(AT& allocator, T const& tval) { return emplace(allocator, tval.size(), reinterpret_cast(tval.data())); } void clear() { m_value = value_type{}; base::clear();} private: value_type m_value; }; /*************************************************************************************** * T_BITSTRING ***************************************************************************************/ template > struct bstring : base { using asn_identifier_t = identifier(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(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(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 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 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 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 struct choice : base { using asn_identifier_t = identifier(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; 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 struct sequence : base { using asn_identifier_t = identifier(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; }; /*************************************************************************************** * T_SEQUENCE_OF ***************************************************************************************/ template > struct sequenceof : base { using asn_identifier_t = identifier(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 > { value_type(){} private: value_type& operator=(const value_type&) = delete; value_type (const value_type&) = delete; }; using values_t = boost::intrusive::list>; using constraint_t = Constraint; using element_t = T; void clear() { m_list.clear(); base::clear();} size_t size() const { return m_list.size(); } template void sort(Predicate const& p) { m_list.sort(p); } template 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 //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 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 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(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 > struct printable_string : ostring { using asn_identifier_t = identifier(tag_rvalue_t::PrintableString), tag_type_t::IMPLICIT>; static constexpr const char* name() {return "PrintableString";} }; /*************************************************************************************** * T_IA5_STRING ***************************************************************************************/ template > struct ia5_string : ostring { using asn_identifier_t = identifier(tag_rvalue_t::IA5String), tag_type_t::IMPLICIT>; static constexpr const char* name() {return "IA5String";} }; /*************************************************************************************** * T_GRAPHIC_STRING ***************************************************************************************/ template > struct graphic_string : ostring { using asn_identifier_t = identifier(tag_rvalue_t::GraphicString), tag_type_t::IMPLICIT>; static constexpr const char* name() {return "IA5String";} }; /*************************************************************************************** * T_UTF8_STRING ***************************************************************************************/ template > struct utf8_string : ostring { using asn_identifier_t = identifier(tag_rvalue_t::UTF8String), tag_type_t::IMPLICIT>; static constexpr const char* name() {return "UTF8String";} }; /*************************************************************************************** * T_SET ***************************************************************************************/ template struct set : base { using asn_identifier_t = identifier(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; }; /*************************************************************************************** * T_SET_OF ***************************************************************************************/ template > struct setof : sequenceof { using asn_identifier_t = identifier(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