blob: 9cbcd4209d57fcce9000c58e5cf021da383d0004 [file] [log] [blame]
#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