Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/vanetza/asn1/asn1c_wrapper.hpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

345 lines
9.7 KiB
C++

#ifndef ASN1C_WRAPPER_HPP_ZCNDO8E5
#define ASN1C_WRAPPER_HPP_ZCNDO8E5
#include <vanetza/asn1/support/asn_system.h>
#include <vanetza/asn1/support/constr_TYPE.h>
#include <vanetza/asn1/type_traits.hpp>
#include <vanetza/common/byte_buffer.hpp>
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
namespace vanetza
{
namespace asn1
{
void* allocate(std::size_t);
void free(asn_TYPE_descriptor_t&, void*);
void* copy(asn_TYPE_descriptor_t&, const void*);
bool validate(asn_TYPE_descriptor_t&, const void*);
bool validate(asn_TYPE_descriptor_t&, const void*, std::string&);
int compare(asn_TYPE_descriptor_t&, const void*, const void*);
int print(FILE* stream, asn_TYPE_descriptor_t&, const void*);
std::size_t size_per(asn_TYPE_descriptor_t&, const void*);
std::size_t size_oer(asn_TYPE_descriptor_t&, const void*);
std::size_t size_xer(asn_TYPE_descriptor_t&, const void*);
ByteBuffer encode_per(asn_TYPE_descriptor_t&, const void*);
bool decode_per(asn_TYPE_descriptor_t&, void**, const ByteBuffer&);
bool decode_per(asn_TYPE_descriptor_t&, void**, const void* buffer, std::size_t size);
ByteBuffer encode_oer(asn_TYPE_descriptor_t&, const void*);
bool decode_oer(asn_TYPE_descriptor_t&, void**, const ByteBuffer&);
bool decode_oer(asn_TYPE_descriptor_t&, void**, const void* buffer, std::size_t size);
ByteBuffer encode_xer(asn_TYPE_descriptor_t&, const void*);
bool decode_xer(asn_TYPE_descriptor_t&, void**, const ByteBuffer&);
bool decode_xer(asn_TYPE_descriptor_t&, void**, const void* buffer, std::size_t size);
template<class T>
T* allocate()
{
return static_cast<T*>(allocate(sizeof(T)));
}
/// Deleter freeing an asn1c struct through its ASN.1 type descriptor.
struct deleter
{
asn_TYPE_descriptor_t* descriptor = nullptr;
void operator()(void* ptr) const;
};
/**
* Allocate an asn1c struct owned by a unique_ptr that deep-frees it via its descriptor.
* \param descriptor ASN.1 type descriptor matching T
* \return owning unique_ptr
*/
template<class T>
std::unique_ptr<T, deleter> make_unique(asn_TYPE_descriptor_t& descriptor)
{
return std::unique_ptr<T, deleter> { allocate<T>(), deleter { &descriptor } };
}
/**
* Allocate an asn1c struct owned by a unique_ptr, taking the type descriptor
* from the asn1_type_traits specialization of T.
* \return owning unique_ptr
*/
template<class T>
std::unique_ptr<T, deleter> make_unique()
{
return make_unique<T>(asn1_type_traits<T>::descriptor());
}
template<class T>
class asn1c_wrapper_common
{
public:
typedef T asn1c_type;
asn1c_wrapper_common(asn_TYPE_descriptor_t& desc) :
m_struct(vanetza::asn1::allocate<asn1c_type>()), m_type(desc) {}
asn1c_wrapper_common(asn_TYPE_descriptor_t& desc, const T* ptr) :
m_struct(static_cast<T*>(copy(desc, ptr))), m_type(desc) {}
~asn1c_wrapper_common() { vanetza::asn1::free(m_type, m_struct); }
// copy semantics
asn1c_wrapper_common(const asn1c_wrapper_common& other) :
m_struct(static_cast<asn1c_type*>(copy(other.m_type, other.m_struct))), m_type(other.m_type) {}
asn1c_wrapper_common& operator=(const asn1c_wrapper_common& other)
{
asn1c_wrapper_common tmp = other;
swap(tmp);
return *this;
}
// move semantics
asn1c_wrapper_common(asn1c_wrapper_common&& other) noexcept :
m_struct(nullptr), m_type(other.m_type) { swap(other); }
asn1c_wrapper_common& operator=(asn1c_wrapper_common&& other) noexcept
{
swap(other);
return *this;
}
// dereferencing
asn1c_type& operator*() { return *m_struct; }
asn1c_type* operator->() { return m_struct; }
const asn1c_type& operator*() const { return *m_struct; }
const asn1c_type* operator->() const { return m_struct; }
// direct access to content structure
const asn1c_type* content() const { return m_struct; }
asn1c_type* content() { return m_struct; }
// compare semantics
bool operator==(const asn1c_wrapper_common& rhs) const
{
return vanetza::asn1::compare(m_type, m_struct, rhs.m_struct) == 0;
}
bool operator!=(const asn1c_wrapper_common& rhs) const
{
return vanetza::asn1::compare(m_type, m_struct, rhs.m_struct) != 0;
}
/**
* Check ASN.1 constraints
* \param error (optional) copy of error message
* \return true if valid
*/
bool validate() const
{
return vanetza::asn1::validate(m_type, m_struct);
}
/**
* Check ASN.1 constraints
* \param error Error message if any constraint failed
* \return true if valid
*/
bool validate(std::string& error) const
{
return vanetza::asn1::validate(m_type, m_struct, error);
}
/**
* Compare ASN.1 types
* \param other Other ASN.1 type to compare with
* \return 0 if equal, <0 if other is "greater", >0 if other is "smaller"
*/
int compare(const asn1c_wrapper_common& other) const
{
return vanetza::asn1::compare(m_type, m_struct, other.m_struct);
}
/**
* Print ASN.1 type to standard output
* \return 0 on success, -1 on error
*/
int print() const
{
return vanetza::asn1::print(stdout, m_type, m_struct);
}
/**
* Print ASN.1 type to some file stream
* \param stream Output stream
* \return 0 on success, -1 on error
*/
int print(FILE* stream) const
{
return vanetza::asn1::print(stream, m_type, m_struct);
}
/**
* Swap ASN.1 wrapper content
* \param other wrapper
*/
void swap(asn1c_wrapper_common& other) noexcept
{
std::swap(m_struct, other.m_struct);
std::swap(m_type, other.m_type);
}
protected:
asn1c_type* m_struct;
asn_TYPE_descriptor_t& m_type;
};
template<typename T>
void swap(asn1c_wrapper_common<T>& lhs, asn1c_wrapper_common<T>& rhs)
{
lhs.swap(rhs);
}
template<class T>
class asn1c_per_wrapper : public asn1c_wrapper_common<T>
{
public:
using base = asn1c_wrapper_common<T>;
using base::base;
/**
* Encode ASN.1 struct into byte buffer
* \return byte buffer containing serialized ASN.1 struct
*/
ByteBuffer encode() const
{
return vanetza::asn1::encode_per(base::m_type, base::m_struct);
}
/**
* Try to decode ASN.1 struct from byte buffer
* \param buffer input data
* \return true if decoding has been successful
*/
bool decode(const ByteBuffer& buffer)
{
return vanetza::asn1::decode_per(base::m_type, (void**)&(base::m_struct), buffer);
}
bool decode(ByteBuffer::const_iterator begin, ByteBuffer::const_iterator end)
{
return vanetza::asn1::decode_per(base::m_type, (void**)&(base::m_struct), &(*begin), std::distance(begin, end));
}
bool decode(const void* buffer, std::size_t len)
{
return vanetza::asn1::decode_per(base::m_type, (void**)&(base::m_struct), buffer, len);
}
/**
* Get size of encoded ASN.1 struct
* \return size in bytes
*/
std::size_t size() const
{
return vanetza::asn1::size_per(base::m_type, base::m_struct);
}
};
template<class T>
using asn1c_wrapper = asn1c_per_wrapper<T>;
template<class T>
class asn1c_oer_wrapper : public asn1c_wrapper_common<T>
{
public:
using base = asn1c_wrapper_common<T>;
using base::base;
/**
* Encode ASN.1 struct into byte buffer
* \return byte buffer containing serialized ASN.1 struct
*/
ByteBuffer encode() const
{
return vanetza::asn1::encode_oer(base::m_type, base::m_struct);
}
/**
* Try to decode ASN.1 struct from byte buffer
* \param buffer input data
* \deprecated use decode_per instead
* \return true if decoding has been successful
*/
bool decode(const ByteBuffer& buffer)
{
return vanetza::asn1::decode_oer(base::m_type, (void**)&(base::m_struct), buffer);
}
bool decode(ByteBuffer::const_iterator begin, ByteBuffer::const_iterator end)
{
return vanetza::asn1::decode_oer(base::m_type, (void**)&(base::m_struct), &(*begin), std::distance(begin, end));
}
bool decode(const void* buffer, std::size_t len)
{
return vanetza::asn1::decode_oer(base::m_type, (void**)&(base::m_struct), buffer, len);
}
/**
* Get size of encoded ASN.1 struct
* \return size in bytes
*/
std::size_t size() const
{
return vanetza::asn1::size_oer(base::m_type, base::m_struct);
}
};
template<class T>
class asn1c_xer_wrapper : public asn1c_wrapper_common<T>
{
public:
using base = asn1c_wrapper_common<T>;
using base::base;
/**
* Encode ASN.1 struct into byte buffer
* \return byte buffer containing serialized ASN.1 struct
*/
ByteBuffer encode() const
{
return vanetza::asn1::encode_xer(base::m_type, base::m_struct);
}
/**
* Try to decode ASN.1 struct from byte buffer
* \param buffer input data
* \return true if decoding has been successful
*/
bool decode(const ByteBuffer& buffer)
{
return vanetza::asn1::decode_xer(base::m_type, (void**)&(base::m_struct), buffer);
}
bool decode(ByteBuffer::const_iterator begin, ByteBuffer::const_iterator end)
{
return vanetza::asn1::decode_xer(base::m_type, (void**)&(base::m_struct), &(*begin), std::distance(begin, end));
}
bool decode(const void* buffer, std::size_t len)
{
return vanetza::asn1::decode_xer(base::m_type, (void**)&(base::m_struct), buffer, len);
}
/**
* Get size of encoded ASN.1 struct
* \return size in bytes
*/
std::size_t size() const
{
return vanetza::asn1::size_xer(base::m_type, base::m_struct);
}
};
} // namespace asn1
} // namespace vanetza
#endif /* ASN1C_WRAPPER_HPP_ZCNDO8E5 */