initial commit for github
This commit is contained in:
commit
60968612de
370 changed files with 68427 additions and 0 deletions
573
codec/access_element.h
Normal file
573
codec/access_element.h
Normal file
|
@ -0,0 +1,573 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
#ifndef DDL_STRUCT_ELEMENT_ACCESS_CLASS_HEADER
|
||||
#define DDL_STRUCT_ELEMENT_ACCESS_CLASS_HEADER
|
||||
|
||||
#include <a_util/result.h>
|
||||
|
||||
#include "struct_element.h"
|
||||
#include "codec_factory.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
namespace access_element
|
||||
{
|
||||
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-3, ERR_UNEXPECTED)
|
||||
_MAKE_RESULT(-20, ERR_NOT_FOUND)
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// For internal use only. @internal
|
||||
template <typename T>
|
||||
static inline size_t getElementCount(const T& type)
|
||||
{
|
||||
return type.getElementCount();
|
||||
}
|
||||
|
||||
/// For internal use only. @internal
|
||||
template <typename T>
|
||||
static inline a_util::result::Result getElement(const T& type, size_t element_index, const StructElement*& element)
|
||||
{
|
||||
return type.getElement(element_index, element);
|
||||
}
|
||||
|
||||
/// For internal use only. @internal
|
||||
template <>
|
||||
inline size_t getElementCount(const CodecFactory& type)
|
||||
{
|
||||
return type.getStaticElementCount();
|
||||
}
|
||||
|
||||
/// For internal use only. @internal
|
||||
template <>
|
||||
inline a_util::result::Result getElement(const CodecFactory& type, size_t element_index, const StructElement*& element)
|
||||
{
|
||||
return type.getStaticElement(element_index, element);
|
||||
}
|
||||
|
||||
/// For internal use only. @internal
|
||||
template <typename T>
|
||||
a_util::result::Result find_complex_index(const T& decoder, const std::string& struct_name,
|
||||
size_t& index, const char* post_fix)
|
||||
{
|
||||
if (struct_name.empty())
|
||||
{
|
||||
index = 0;
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
size_t element_count = getElementCount(decoder);
|
||||
std::string prefix = struct_name + post_fix;
|
||||
for (size_t element_index = 0; element_index < element_count; ++element_index)
|
||||
{
|
||||
const StructElement* element;
|
||||
if (isOk(getElement(decoder, element_index, element)))
|
||||
{
|
||||
|
||||
if (a_util::strings::compare(element->name.c_str(), prefix.c_str(), 0, prefix.size()) == 0)
|
||||
{
|
||||
index = element_index;
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* find the index of an element by name.
|
||||
* @param[in] decoder The decoder or factory.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @param[out] index The index of the found element.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result find_index(const T& decoder, const std::string& element_name, size_t& index)
|
||||
{
|
||||
size_t element_count = detail::getElementCount(decoder);
|
||||
for (size_t element_index = 0; element_index < element_count; ++element_index)
|
||||
{
|
||||
const StructElement* element;
|
||||
if (isOk(detail::getElement(decoder, element_index, element)))
|
||||
{
|
||||
if (element->name == element_name)
|
||||
{
|
||||
index = element_index;
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* find the index of the first element of a sub-structure by name.
|
||||
* @param[in] decoder The decoder or factory.
|
||||
* @param[in] struct_name The name of the sub-structure.
|
||||
* @param[out] index The index of the found element.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result find_struct_index(const T& decoder, const std::string& struct_name, size_t& index)
|
||||
{
|
||||
return detail::find_complex_index<T>(decoder, struct_name, index, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* find the index of the first element of an array by name.
|
||||
* @param[in] decoder The decoder or factory.
|
||||
* @param[in] array_name The name of the array.
|
||||
* @param[out] index The index of the found element.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result find_array_index(const T& decoder, const std::string& array_name, size_t& index)
|
||||
{
|
||||
return detail::find_complex_index<T>(decoder, array_name, index, "[");
|
||||
}
|
||||
|
||||
/**
|
||||
* find the index of the first element after an array by name.
|
||||
* @param[in] decoder The decoder or factory.
|
||||
* @param[in] array_name The name of the array.
|
||||
* @param[out] index The index of the found element.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result find_array_end_index(const T& decoder, const std::string& array_name, size_t& index)
|
||||
{
|
||||
size_t element_count = detail::getElementCount(decoder);
|
||||
std::string prefix = array_name + "[";
|
||||
for (index += 1; index < element_count; ++index)
|
||||
{
|
||||
const StructElement* element;
|
||||
if (isFailed(detail::getElement(decoder, index, element)))
|
||||
{
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
if (a_util::strings::compare(element->name.c_str(), prefix.c_str(), 0, prefix.size()) != 0)
|
||||
{
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of an element by name.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @param[out] value The location where the value should be copied to.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result get_value(const T& decoder, const std::string& element_name, void* value)
|
||||
{
|
||||
size_t element_index;
|
||||
a_util::result::Result res = find_index(decoder, element_name, element_index);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
return decoder.getElementValue(element_index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of an element by name.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @param[in] value The location where the value should be copied from.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result set_value(T& codec, const std::string& element_name, const void* value)
|
||||
{
|
||||
size_t element_index;
|
||||
a_util::result::Result res = find_index(codec, element_name, element_index);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
return codec.setElementValue(element_index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of an element by name.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @retval The value of the element.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::variant::Variant get_value(const T& decoder, const std::string& element_name)
|
||||
{
|
||||
a_util::variant::Variant result;
|
||||
size_t element_index;
|
||||
if (isOk(find_index(decoder, element_name, element_index)))
|
||||
{
|
||||
decoder.getElementValue(element_index, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of an element by name.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @param[in] value The new value.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result set_value(T& codec, const std::string& element_name, const a_util::variant::Variant& value)
|
||||
{
|
||||
size_t element_index;
|
||||
a_util::result::Result res = find_index(codec, element_name, element_index);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
return codec.setElementValue(element_index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of an element by index.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] element_index The index of the element.
|
||||
* @retval The value of the element.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::variant::Variant get_value(const T& decoder, size_t element_index)
|
||||
{
|
||||
a_util::variant::Variant result;
|
||||
if (isOk(decoder.getElementValue(element_index, result)))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return a_util::variant::Variant(static_cast<int32_t>(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to an element by name.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @return Address of the element.
|
||||
*/
|
||||
template <typename T>
|
||||
const void* get_value_address(const T& decoder, const std::string& element_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_index(decoder, element_name, element_index)))
|
||||
{
|
||||
return decoder.getElementAddress(element_index);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to an element by name.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @return Address of the element.
|
||||
*/
|
||||
template <typename T>
|
||||
void* get_value_address(T& codec, const std::string& element_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_index(codec, element_name, element_index)))
|
||||
{
|
||||
return codec.getElementAddress(element_index);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to a sub-structure by name.
|
||||
* @param[in] decoder The codec.
|
||||
* @param[in] struct_name The name of the structure.
|
||||
* @return Address of the sub-structure.
|
||||
*/
|
||||
template <typename STRUCT, typename T>
|
||||
const STRUCT* get_struct_address(const T& decoder, const std::string& struct_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_struct_index(decoder, struct_name, element_index)))
|
||||
{
|
||||
return reinterpret_cast<const STRUCT*>(decoder.getElementAddress(element_index));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to a sub-structure by name.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] struct_name The name of the structure.
|
||||
* @return Address of the sub-structure.
|
||||
*/
|
||||
template <typename STRUCT, typename T>
|
||||
STRUCT* get_struct_address(T& codec, const std::string& struct_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_struct_index(codec, struct_name, element_index)))
|
||||
{
|
||||
return reinterpret_cast<STRUCT*>(codec.getElementAddress(element_index));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a sub-structure out of the structure.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] struct_name The name of the structure.
|
||||
* @param[out] struct_value The location the sub-structure will be copied to.
|
||||
* @retval ERR_NOT_FOUND No structure with the requested name was found.
|
||||
*/
|
||||
template <typename T, typename CODEC>
|
||||
a_util::result::Result get_struct_value(const CODEC& decoder, const std::string& struct_name, T* struct_value)
|
||||
{
|
||||
const T* address = get_struct_address<T>(decoder, struct_name);
|
||||
if (!address)
|
||||
{
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
a_util::memory::copy(struct_value, sizeof(T), address, sizeof(T));
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a sub-structure into the structure.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] struct_name The name of the structure.
|
||||
* @param[in] struct_value The location the sub-structure will be copied from.
|
||||
* @retval ERR_NOT_FOUND No structure with the requested name was found.
|
||||
*/
|
||||
template <typename T, typename CODEC>
|
||||
a_util::result::Result set_struct_value(CODEC& codec, const std::string& struct_name, const T* struct_value)
|
||||
{
|
||||
T* address = get_struct_address<T>(codec, struct_name);
|
||||
if (!address)
|
||||
{
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
a_util::memory::copy(address, sizeof(T), struct_value, sizeof(T));
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to an array by name.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] array_name The name of the array.
|
||||
* @return Address of the array.
|
||||
*/
|
||||
template <typename ARRAY_TYPE, typename T>
|
||||
const ARRAY_TYPE* get_array_address(const T& decoder, const std::string& array_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_array_index(decoder, array_name, element_index)))
|
||||
{
|
||||
return reinterpret_cast<const ARRAY_TYPE*>(decoder.getElementAddress(element_index));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to an array by name.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] array_name The name of the array.
|
||||
* @return Address of the array.
|
||||
*/
|
||||
template <typename ARRAY_TYPE, typename T>
|
||||
ARRAY_TYPE* get_array_address(T& codec, const std::string& array_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_array_index(codec, array_name, element_index)))
|
||||
{
|
||||
return reinterpret_cast<ARRAY_TYPE*>(codec.getElementAddress(element_index));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about an array.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] array_name The name of the array.
|
||||
* @param[out] start_address The address of the first element of the array.
|
||||
* @param[out] size The amount of elements of the array.
|
||||
* @retval ERR_NOT_FOUND No array with the requested name was found.
|
||||
*/
|
||||
template <typename CODEC>
|
||||
a_util::result::Result get_array(const CODEC& decoder, const std::string& array_name,
|
||||
const void*& start_address, size_t& size)
|
||||
{
|
||||
size_t start_index = 0;
|
||||
a_util::result::Result res = find_array_index(decoder, array_name, start_index);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
size_t end_index = start_index;
|
||||
res = find_array_end_index(decoder, array_name, end_index);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
start_address = decoder.getElementAddress(start_index);
|
||||
if (!start_address)
|
||||
{
|
||||
return ERR_UNEXPECTED;
|
||||
}
|
||||
|
||||
const void* end_adress = decoder.getElementAddress(end_index);
|
||||
if (end_adress)
|
||||
{
|
||||
size = static_cast<const uint8_t*>(end_adress) -
|
||||
static_cast<const uint8_t*>(start_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it reaches til the end
|
||||
size_t start_offset = static_cast<const uint8_t*>(start_address) -
|
||||
static_cast<const uint8_t*>(decoder.getElementAddress(0));
|
||||
size = decoder.getBufferSize(decoder.getRepresentation()) - start_offset;
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an array out of the structure.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] array_name The name of the array.
|
||||
* @param[out] array_value The location the array will be copied to.
|
||||
* @retval ERR_NOT_FOUND No array with the requested name was found.
|
||||
*/
|
||||
template <typename T, typename CODEC>
|
||||
a_util::result::Result get_array_value(const CODEC& decoder, const std::string& array_name, T* array_value)
|
||||
{
|
||||
const void* start_address;
|
||||
size_t size;
|
||||
a_util::result::Result res = get_array(decoder, array_name, start_address, size);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
a_util::memory::copy(array_value, size, start_address, size);
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the requested element to zero.
|
||||
* @param[in] codec The codec.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @retval ERR_NOT_FOUND No element with the requested name was found.
|
||||
*/
|
||||
template <typename T>
|
||||
a_util::result::Result reset(T& codec, const std::string& element_name)
|
||||
{
|
||||
size_t element_index;
|
||||
a_util::result::Result res = find_index(codec, element_name, element_index);
|
||||
if (a_util::result::isFailed(res)) return res;
|
||||
|
||||
uint64_t zero = 0;
|
||||
return codec.setElementValue(element_index, &zero);
|
||||
}
|
||||
|
||||
///For internal use only. @internal
|
||||
#define GET_ENUM_CASE(__variant_type, __data_type) \
|
||||
case a_util::variant::VT_##__variant_type:\
|
||||
{\
|
||||
__data_type xValue = value.get##__variant_type();\
|
||||
for (EnumType::const_iterator it = element->p_enum->begin(); it != element->p_enum->end(); ++it)\
|
||||
{\
|
||||
if (xValue == it->second.as##__variant_type())\
|
||||
{\
|
||||
return it->first;\
|
||||
}\
|
||||
}\
|
||||
break;\
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of an element as a string, using enum value names if available.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] element The index of the element.
|
||||
* @return A string representation of the value.
|
||||
*/
|
||||
template <typename T>
|
||||
std::string get_value_as_string(const T& decoder, size_t element_index)
|
||||
{
|
||||
a_util::variant::Variant value;
|
||||
const StructElement* element;
|
||||
if (isOk(decoder.getElement(element_index, element)))
|
||||
{
|
||||
if (isOk(decoder.getElementValue(element_index, value)))
|
||||
{
|
||||
if (element->p_enum)
|
||||
{
|
||||
switch (value.getType())
|
||||
{
|
||||
GET_ENUM_CASE(Bool, bool)
|
||||
GET_ENUM_CASE(Int8, int8_t)
|
||||
GET_ENUM_CASE(UInt8, uint8_t)
|
||||
GET_ENUM_CASE(Int16, int16_t)
|
||||
GET_ENUM_CASE(UInt16, uint16_t)
|
||||
GET_ENUM_CASE(Int32, int32_t)
|
||||
GET_ENUM_CASE(UInt32, uint32_t)
|
||||
GET_ENUM_CASE(Int64, int64_t)
|
||||
GET_ENUM_CASE(UInt64, uint64_t)
|
||||
GET_ENUM_CASE(Float, float)
|
||||
GET_ENUM_CASE(Double, double)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value.asString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of an element as a string, using enum value names if available.
|
||||
* @param[in] decoder The decoder.
|
||||
* @param[in] element_name The name of the element.
|
||||
* @return A string representation of the value.
|
||||
*/
|
||||
template <typename T>
|
||||
std::string get_value_as_string(const T& decoder, const std::string& element_name)
|
||||
{
|
||||
size_t element_index;
|
||||
if (isOk(find_index(decoder, element_name, element_index)))
|
||||
{
|
||||
return get_value_as_string(decoder, element_index);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
97
codec/bitserializer.cpp
Normal file
97
codec/bitserializer.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* @file
|
||||
* Raw memory related functionality
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#include "a_util/memory.h"
|
||||
#include "bitserializer.h"
|
||||
|
||||
using namespace a_util;
|
||||
using namespace a_util::memory;
|
||||
|
||||
|
||||
a_util::memory::Endianess a_util::memory::get_platform_endianess()
|
||||
{
|
||||
uint32_t value = 0x01020304;
|
||||
if (((unsigned char*)&value)[0] == 0x04 &&
|
||||
((unsigned char*)&value)[2] == 0x02)
|
||||
{
|
||||
return bit_little_endian;
|
||||
}
|
||||
else if (((unsigned char*)&value)[0] == 0x01 &&
|
||||
((unsigned char*)&value)[2] == 0x03)
|
||||
{
|
||||
return bit_big_endian;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("unsupported endianess");
|
||||
}
|
||||
}
|
||||
|
||||
std::string a_util::memory::detail::formatBits(uint64_t value)
|
||||
{
|
||||
std::string bit_string;
|
||||
|
||||
for (int i = 0; i < (int)sizeof(uint64_t) * 8; i++)
|
||||
{
|
||||
if (i % 8 == 0)
|
||||
{
|
||||
bit_string += " | ";
|
||||
}
|
||||
bit_string += a_util::strings::toString((value >> (63 - i)) & 1);
|
||||
}
|
||||
|
||||
return bit_string;
|
||||
}
|
||||
|
||||
a_util::result::Result a_util::memory::detail::convertSignalEndianess(uint64_t *signal, Endianess endianess, size_t bit_length)
|
||||
{
|
||||
if (bit_length > 8) // Signal is bigger than one byte
|
||||
{
|
||||
if (endianess != get_platform_endianess()) // Byteorder was different on writing platform
|
||||
{
|
||||
if (bit_length > (4 * 8)) // 64 Bit
|
||||
{
|
||||
// If the BE signal is shorter than 8 byte, make sure the value is aligned
|
||||
// at the LSB end, seen from a BE viewpoint.
|
||||
if (endianess == bit_big_endian)
|
||||
{
|
||||
*signal <<= (((8 * 8) - (bit_length)) / 8) * 8;
|
||||
}
|
||||
*reinterpret_cast<uint64_t*>(signal) = a_util::memory::swapEndianess(*reinterpret_cast<uint64_t*>(signal));
|
||||
}
|
||||
else if (bit_length > (2 * 8)) // 32 Bit
|
||||
{
|
||||
// If the BE signal is shorter than 4 byte, make sure the value is aligned
|
||||
// at the LSB end, seen from a BE viewpoint.
|
||||
if (endianess == bit_big_endian)
|
||||
{
|
||||
*signal <<= (((4 * 8) - (bit_length)) / 8) * 8;
|
||||
}
|
||||
*reinterpret_cast<uint32_t*>(signal) = a_util::memory::swapEndianess(*reinterpret_cast<uint32_t*>(signal));
|
||||
}
|
||||
else // 16 Bit
|
||||
{
|
||||
*reinterpret_cast<uint16_t*>(signal) = a_util::memory::swapEndianess(*reinterpret_cast<uint16_t*>(signal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
750
codec/bitserializer.h
Normal file
750
codec/bitserializer.h
Normal file
|
@ -0,0 +1,750 @@
|
|||
/**
|
||||
* @file
|
||||
* Raw memory related functionality
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
#ifndef A_UTILS_UTIL_MEMORY_BITSERIALIZER_INCLUDED
|
||||
#define A_UTILS_UTIL_MEMORY_BITSERIALIZER_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "a_util/memory.h"
|
||||
#include "a_util/result.h"
|
||||
|
||||
namespace a_util
|
||||
{
|
||||
namespace memory
|
||||
{
|
||||
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-4, ERR_POINTER);
|
||||
_MAKE_RESULT(-5, ERR_INVALID_ARG);
|
||||
|
||||
/// Enum describing the endianess
|
||||
typedef enum
|
||||
{
|
||||
bit_little_endian = 1,
|
||||
bit_big_endian = 2,
|
||||
} Endianess;
|
||||
|
||||
/**
|
||||
* Returns the endianess of the platform
|
||||
* @return See \ref Endianess
|
||||
*/
|
||||
Endianess get_platform_endianess();
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Format the bit pattern of a uint64_t value to a string
|
||||
* Used for debug purposes.
|
||||
*
|
||||
* @param [in] value The value to print.
|
||||
* @retval The bitstring
|
||||
*/
|
||||
std::string formatBits(uint64_t value);
|
||||
|
||||
/**
|
||||
* Convert the endianess of a signal by correctly swapping the byte order if required.
|
||||
* The variable signal is a uint64_t, but the value that needs conversion might be smaller.
|
||||
* The parameter bit_length determines if a 16, 32 or 64 value should be swapped.
|
||||
* For a LE system, reading BE signals of 3, 5, 6 or 7 bytes length the value will be aligned
|
||||
* within a 4 or 8 byte value before swapping bytes.
|
||||
*
|
||||
* @param [in,out] signal Pointer to the variable to store the read value in.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to convert.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
a_util::result::Result convertSignalEndianess(uint64_t *signal, Endianess endianess, size_t bit_length);
|
||||
|
||||
/**
|
||||
* Converter Base
|
||||
* Contains the base methods used by all inheriting Converter classes.
|
||||
*/
|
||||
template<typename T>
|
||||
class ConverterBase {
|
||||
protected:
|
||||
/**
|
||||
* Read value from bitfield.
|
||||
* Operating on a uint64_t copy to allow bit shifting and masking operations.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to read from.
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [out] value Pointer to the variable to store the read value in.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to read from.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result readSignal(uint8_t *buffer, size_t start_bit, size_t bit_length, T* value,
|
||||
Endianess endianess = get_platform_endianess())
|
||||
{
|
||||
/*
|
||||
* offset_end offset_start
|
||||
* _ ____
|
||||
* | | | |
|
||||
* ....|...abcde|fghijklm|no......|.... Buffer (index 0 on the right end side)
|
||||
* |_______________|
|
||||
* bit_length ^
|
||||
* |
|
||||
* start_bit
|
||||
*/
|
||||
|
||||
// 1) COPY relevant bytes of Buffer content to result variable.
|
||||
uint64_t result = 0; // Result value
|
||||
uint64_t ninth_byte = 0; // variable to eventually store a ninth byte from buffer
|
||||
size_t bytes_to_read = 0;
|
||||
copyBytesFromBuffer(buffer, &result, start_bit, bit_length, &ninth_byte, &bytes_to_read);
|
||||
|
||||
// 2) TRIM unrelevant bits and SHIFT to align value.
|
||||
|
||||
// Number of bits the start position is offset from 0 (0 for aligned signal)
|
||||
size_t offset_start = start_bit % 8;
|
||||
// Number of bits the end position is offset from the end of the last byte (0 for complete bytes)
|
||||
size_t offset_end = (8 - ((start_bit + bit_length) % 8)) % 8;
|
||||
|
||||
/**********************************************************************************************
|
||||
* Distinguish between LE and BE operating systems to get the shift operations right *
|
||||
**********************************************************************************************/
|
||||
// On LE System
|
||||
if (get_platform_endianess() == bit_little_endian)
|
||||
{
|
||||
/* Use bit mask to remove bits on the higher end, which do not belong to the value to read.
|
||||
*
|
||||
* ...|...abcde|fghijklm|no......| => 000|000abcde|fghijklm|no......|
|
||||
*
|
||||
*/
|
||||
cutLeadingBits(&result, bit_length + offset_start);
|
||||
|
||||
/* Shift right to align start at position 0 (also trims the right end).
|
||||
*
|
||||
* 000|000abcde|fghijklm|no......| => 000|00000000|0abcdefg|hijklmno|
|
||||
*
|
||||
*/
|
||||
result >>= offset_start;
|
||||
|
||||
// Eventually get bits from the copied 9th byte.
|
||||
if (ninth_byte > 0) // nothing to take care of if nothing was copied or all copied bits are 0.
|
||||
{
|
||||
// deleteAll unwanted bits from ninth byte.
|
||||
cutLeadingBits(&ninth_byte, (8 - offset_end));
|
||||
size_t bit_size = sizeof(result) * 8;
|
||||
// Shift requested bits from the 9th byte into the right position to be combined with result.
|
||||
ninth_byte <<= (bit_size - offset_start);
|
||||
// merge value together from all nine bytes.
|
||||
result = result | ninth_byte;
|
||||
}
|
||||
|
||||
// BE Signal needs byte order swapping.
|
||||
if (endianess == bit_big_endian)
|
||||
{
|
||||
// Only for reading partial bytes. Filling the missing bits differs from LE Signal.
|
||||
if (bit_length % 8 != 0)
|
||||
{
|
||||
/* Shift left to align end position.
|
||||
*
|
||||
* 000|0abcdefg|hijklmno| => 000|abcdefgh|ijklmno0|
|
||||
*
|
||||
*/
|
||||
result <<= (offset_end + offset_start) % 8;
|
||||
|
||||
/* Shift bits within MSByte, filling the gap with 0s.
|
||||
*
|
||||
* 000|abcdefgh|ijklmno0| => 000|abcdefgh|0ijklmno|
|
||||
* ^ ^
|
||||
* MSByte MSByte
|
||||
*/
|
||||
uint8_t *ms_byte = (uint8_t*)&result;
|
||||
ms_byte[0] >>= (offset_end + offset_start) % 8;
|
||||
}
|
||||
|
||||
/* swap bytes to LE.
|
||||
*
|
||||
* 000|abcdefgh|0ijklmno| => 000|0ijklmno|abcdefgh|
|
||||
*
|
||||
*/
|
||||
detail::convertSignalEndianess(&result, endianess, bit_length);
|
||||
}
|
||||
}
|
||||
// On BE System
|
||||
else
|
||||
{
|
||||
/* swap bytes to simulate LE shifting operations.
|
||||
*
|
||||
* |...abcde|fghijklm|no......|... => ...|no......|fghijklm|...abcde|
|
||||
*
|
||||
*/
|
||||
detail::convertSignalEndianess(&result, bit_little_endian, sizeof(result) * 8);
|
||||
|
||||
// LE Signal
|
||||
if (endianess == bit_little_endian)
|
||||
{
|
||||
/* Use bit mask to remove bits on the higher end, which do not belong to the value to read.
|
||||
*
|
||||
* ...|no......|fghijklm|...abcde| => ...|no......|fghijklm|000abcde|
|
||||
*
|
||||
*/
|
||||
cutLeadingBits(&result, (sizeof(result) * 8) - offset_end); // Cut away only offset_end bits.
|
||||
|
||||
/* Shift right to align bits within LSByte (BE Shifting!).
|
||||
*
|
||||
* ...|no......|fghijklm|000abcde| => ...|hijklmno|0abcdefg|00000000|
|
||||
*
|
||||
*/
|
||||
result >>= offset_start;
|
||||
|
||||
/* Shift right to align LSByte on the left side (BE Shifting!).
|
||||
*
|
||||
* ...|hijklmno|0abcdefg|00000000| => |hijklmno|0abcdefg|000
|
||||
*
|
||||
* Shift over all
|
||||
* empty bytes = (all bits - occupied bits (bit_length) - already shifted bits) / number of bytes
|
||||
*/
|
||||
result >>= (((sizeof(result) * 8) - bit_length - offset_start) / sizeof(result)) * 8;
|
||||
|
||||
// No further byte swap, because there has been one swap before the shift operations already.
|
||||
}
|
||||
// BE Signal
|
||||
else
|
||||
{
|
||||
/* Shift left to align bits within LSByte (now rightmost byte because of byte swap).
|
||||
* Also deletes bits from end offset.
|
||||
*
|
||||
* ...|no......|fghijklm|...abcde| => ...|........|ijklmno.|abcdefgh|
|
||||
*
|
||||
*/
|
||||
result <<= offset_end;
|
||||
|
||||
// Only for reading partial bytes. Filling the missing bits differs from LE Signal.
|
||||
if (bit_length % 8 != 0)
|
||||
{
|
||||
/* Shift bits within MSByte to move 0s to the highest bits (also deleting all unwanted bits from start offset).
|
||||
*
|
||||
* ...|........|ijklmno.|abcdefgh| => ...|........|0ijklmno|abcdefgh|
|
||||
*
|
||||
*/
|
||||
uint8_t *ms_byte = (uint8_t*)&result + (bit_length / 8); // position of the value's MSByte
|
||||
ms_byte[0] >>= (offset_end + offset_start) % 8; // amount of unused bits within MSByte
|
||||
}
|
||||
|
||||
/* swap bytes back to BE
|
||||
*
|
||||
* ...|........|0ijklmno|abcdefgh| => |abcdefgh|0ijklmno|...
|
||||
*
|
||||
*/
|
||||
detail::convertSignalEndianess(&result, bit_little_endian, sizeof(result) * 8); // Change the simulated LE value back
|
||||
|
||||
/* Use bit mask to remove bits on the higher end, which do not belong to the value to read.
|
||||
*
|
||||
* |abcdefgh|0ijklmno|... => |abcdefgh|0ijklmno|000
|
||||
*
|
||||
* Remove everything behind the value length plus the gap within MSByte.
|
||||
*/
|
||||
cutLeadingBits(&result, bit_length + (offset_end + offset_start) % 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the resulting value to the target variable. No Casting! Data might be lost otherwise.
|
||||
size_t sz = std::min(sizeof(*value), sizeof(result));
|
||||
a_util::memory::copy(value, sz, &result, sz);
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value to bitfield.
|
||||
* Operating on a uint64_t copy to allow bit shifting and masking operations.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to write to.
|
||||
* @param [in] start_bit Bit position to start writing to. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to write.
|
||||
* @param [out] value Value to write to the bitfield.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to write to.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result writeSignal(uint8_t *buffer, size_t start_bit, size_t bit_length, T value,
|
||||
Endianess endianess = get_platform_endianess())
|
||||
{
|
||||
// 1) Copy relevant bytes of Buffer content to be overwritten.
|
||||
uint64_t buffer_copy = 0;
|
||||
uint64_t ninth_byte = 0; // storage variable for the ninth bit from buffer
|
||||
size_t bytes_to_read = 0;
|
||||
copyBytesFromBuffer(buffer, &buffer_copy, start_bit, bit_length, &ninth_byte, &bytes_to_read);
|
||||
|
||||
// 2) Erase Bits from Buffer copy that will be overwritten TODO: BE LE system difference important here?
|
||||
// Number of bits the start position is offset from 0
|
||||
size_t offset_start = start_bit % 8;
|
||||
// Number of bits the end position is offset from the end of the last byte
|
||||
size_t offset_end = (8 - ((start_bit + bit_length) % 8)) % 8;
|
||||
uint64_t mask_left = ~0ULL;
|
||||
if ((bit_length + offset_start) >= (sizeof(mask_left) * 8))
|
||||
{
|
||||
mask_left = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask_left = ~0ULL;
|
||||
mask_left <<= (bit_length + offset_start);
|
||||
}
|
||||
uint64_t mask = ~0ULL;
|
||||
mask <<= offset_start;
|
||||
mask = ~mask;
|
||||
mask |= mask_left;
|
||||
|
||||
buffer_copy &= mask;
|
||||
|
||||
// 3) Copy value to UInt64 variable to work with.
|
||||
uint64_t signal;
|
||||
a_util::memory::copy(&signal, sizeof(signal), &value, sizeof(signal));
|
||||
|
||||
// 4) Keep only nLength bits: Remove bits that should not be written to the Buffer.
|
||||
cutLeadingBits(&signal, bit_length);
|
||||
|
||||
// 5) Shift to align at start bit position.
|
||||
int shift_amount = (int)offset_start; // Initialized to fit LE Signal shift
|
||||
|
||||
// BE Signal
|
||||
if (endianess == bit_big_endian)
|
||||
{
|
||||
// swap bytes
|
||||
detail::convertSignalEndianess(&signal, endianess, bit_length);
|
||||
// Remove gap for partial bytes within MSByte
|
||||
uint8_t *ms_byte = (uint8_t*)&signal;
|
||||
int ms_shift = (8 - (bit_length % 8)) % 8;
|
||||
ms_byte[0] <<= ms_shift;
|
||||
shift_amount -= ms_shift;
|
||||
}
|
||||
|
||||
// Copy most significant byte to ninth buffer byte before losing bits with the shift.
|
||||
if ((offset_start + bit_length) > (sizeof(signal) * 8))
|
||||
{
|
||||
uint64_t signal_for_ninth_byte = signal;
|
||||
signal_for_ninth_byte >>= (sizeof(signal) - 1) * 8;
|
||||
signal_for_ninth_byte >>= (8 - offset_start); // Only LE Signal
|
||||
uint64_t mask = ~0ULL;
|
||||
mask <<= (8 - offset_end);
|
||||
ninth_byte &= mask;
|
||||
ninth_byte |= signal_for_ninth_byte;
|
||||
}
|
||||
|
||||
if (shift_amount < 0)
|
||||
{
|
||||
signal >>= std::abs(shift_amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
signal <<= shift_amount;
|
||||
}
|
||||
|
||||
// 7) Write bytes with integrated signal back to the buffer.
|
||||
buffer_copy |= signal;
|
||||
|
||||
size_t sz = std::min(bytes_to_read, sizeof(signal));
|
||||
a_util::memory::copy(buffer + (start_bit / 8), sz, &buffer_copy, sz);
|
||||
|
||||
// Eventually copy ninth byte back to buffer
|
||||
if (bytes_to_read > sizeof(signal))
|
||||
{
|
||||
a_util::memory::copy(buffer + (start_bit / 8) + sizeof(signal), 1, &ninth_byte, 1);
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the highest bits of a uint64_t value to zero. The number of bit_length lowest bits
|
||||
* remain unchanged.
|
||||
*
|
||||
* @param [out] value Pointer to the variable to trim.
|
||||
* @param [in] bit_length Number of trailing bits to remain unchanged.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result cutLeadingBits(uint64_t *value, size_t bit_length)
|
||||
{
|
||||
size_t bit_size = (sizeof(*value) * 8);
|
||||
if (bit_length < bit_size)
|
||||
{
|
||||
uint64_t mask = ~0ULL;
|
||||
mask >>= (bit_size - bit_length);
|
||||
*value &= mask;
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes_to_read number of bytes from the buffer to value and ninth_byte.
|
||||
* Determines how many bytes need to be copied to receive a copy of all bits in the range described
|
||||
* by start_bit and bit_length. The maximum for bit_length is 64, but for unaligned values the range
|
||||
* may exceed 8 bytes. In this case, the required ninth byte will be copied to ninth_byte.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to copy from.
|
||||
* @param [out] value Pointer to the variable to store the copied value in.
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [out] ninth_byte Pointer to the variable to eventually store a copied ninth byte in.
|
||||
* @param [out] bytes_to_read Number of bytes that need to be copied to attain all requested bits.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result copyBytesFromBuffer(uint8_t *buffer, uint64_t *value, size_t start_bit, size_t bit_length, uint64_t *ninth_byte, size_t *bytes_to_read)
|
||||
{
|
||||
// Byte within the buffer to start reading at
|
||||
size_t start_byte = start_bit / 8;
|
||||
|
||||
// Number of bits to read: signal length + bits to fill in the offset on both sides for unaligned signals
|
||||
size_t bits_to_read = bit_length + (start_bit % 8);
|
||||
if ((bits_to_read % 8) > 0)
|
||||
{
|
||||
bits_to_read += (8 - (bits_to_read % 8));
|
||||
}
|
||||
// Number of bytes to read from the buffer
|
||||
*bytes_to_read = bits_to_read / 8;
|
||||
|
||||
// Copy up to 8 bytes to result
|
||||
if (*bytes_to_read > (size_t)sizeof(*value))
|
||||
{
|
||||
a_util::memory::copy(value, sizeof(*value), buffer + start_byte, sizeof(*value));
|
||||
}
|
||||
else
|
||||
{
|
||||
a_util::memory::copy(value, *bytes_to_read, buffer + start_byte, *bytes_to_read);
|
||||
}
|
||||
|
||||
// The max signal size is 8 byte, but if the signal is not aligned, it might spread over 9 bytes.
|
||||
|
||||
if (*bytes_to_read > sizeof(*value))
|
||||
{
|
||||
// Get a copy of the most significant byte, which could not yet be saved to result
|
||||
a_util::memory::copy(ninth_byte, 1, buffer + start_byte + sizeof(*value), 1);
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
/// Template converter class to differentiate between float, signed and unsigned integer values.
|
||||
template<typename T, int is_signed, int is_floating_point> class Converter;
|
||||
|
||||
/// Partially specialized class for Unsigned Integers
|
||||
template<typename T>
|
||||
class Converter<T, 0, 0> : public ConverterBase<T>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Read unsigned integer from bitfield.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to read from.
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [out] value Pointer to the variable to store the read value in.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to read from.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result read(uint8_t *buffer, size_t start_bit, size_t bit_length, T* value,
|
||||
Endianess endianess)
|
||||
{
|
||||
return ConverterBase<T>::readSignal(buffer, start_bit, bit_length, value, endianess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write unsigned integer to bitfield.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to write to.
|
||||
* @param [in] start_bit Bit position to start writing to. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to write.
|
||||
* @param [out] value Value to write to the bitfield.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to write to.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result write(uint8_t *buffer, size_t start_bit, size_t bit_length, T value,
|
||||
Endianess endianess)
|
||||
{
|
||||
return ConverterBase<T>::writeSignal(buffer, start_bit, bit_length, value, endianess);
|
||||
}
|
||||
};
|
||||
|
||||
/// Partially specialized class for Signed Integers
|
||||
template<typename T>
|
||||
class Converter<T, 1, 0> : public ConverterBase<T>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Read signed integer from bitfield.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to read from.
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [out] value Pointer to the variable to store the read value in.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to read from.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result read(uint8_t *buffer, size_t start_bit, size_t bit_length, T* value,
|
||||
Endianess endianess)
|
||||
{
|
||||
a_util::result::Result res = ConverterBase<T>::readSignal(buffer, start_bit, bit_length, value, endianess);
|
||||
if (res != a_util::result::SUCCESS)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// replicate sign bit
|
||||
*value <<= (sizeof(T) * 8) - bit_length;
|
||||
*value >>= (sizeof(T) * 8) - bit_length;
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write signed integer to bitfield.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to write to.
|
||||
* @param [in] start_bit Bit position to start writing to. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to write.
|
||||
* @param [out] value Value to write to the bitfield.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to write to.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result write(uint8_t *buffer, size_t start_bit, size_t bit_length, T value,
|
||||
Endianess endianess)
|
||||
{
|
||||
// Nothing special to take care of for writing signed integers, compared to writing unsigned integers.
|
||||
return ConverterBase<T>::writeSignal(buffer, start_bit, bit_length, value, endianess);
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialized class for Floats (Floats are always signed!)
|
||||
template<typename T>
|
||||
class Converter<T, 1, 1> : public ConverterBase<T>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Read tFloat from bitfield.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to read from.
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [out] value Pointer to the variable to store the read value in.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to read from.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result read(uint8_t *buffer, size_t start_bit, size_t bit_length, T* value,
|
||||
Endianess endianess)
|
||||
{
|
||||
// Read only values of size tFloat
|
||||
if (sizeof(T) * 8 == bit_length)
|
||||
{
|
||||
return ConverterBase<T>::readSignal(buffer, start_bit, bit_length, value, endianess);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write tFloat to bitfield.
|
||||
*
|
||||
* @param [in] buffer Pointer to the memory buffer to write to.
|
||||
* @param [in] start_bit Bit position to start writing to. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to write.
|
||||
* @param [out] value Value to write to the bitfield.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to write to.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
static a_util::result::Result write(uint8_t *buffer, size_t start_bit, size_t bit_length, T value,
|
||||
Endianess endianess)
|
||||
{
|
||||
// Write only values of size tFloat
|
||||
if (sizeof(T) * 8 == bit_length)
|
||||
{
|
||||
return ConverterBase<T>::writeSignal(buffer, start_bit, bit_length, value, endianess);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Bit Serializer Class
|
||||
class BitSerializer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
BitSerializer(void* data, size_t data_size) :
|
||||
_buffer(static_cast<uint8_t*>(data)), _buffer_bytes(data_size),
|
||||
_buffer_bits(_buffer_bytes * 8)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
BitSerializer() : _buffer(NULL), _buffer_bytes(0), _buffer_bits(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Read value from bitfield. Value can be of type tFloat or an unsigned or signed integer.
|
||||
*
|
||||
* ....|...*****|********|**......|.... Buffer (index 0 on the right end side)
|
||||
* |_______________|
|
||||
* bit_length ^
|
||||
* |
|
||||
* start_bit
|
||||
*
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [out] value Pointer to the variable to store the read value in.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to read from.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
template<typename T>
|
||||
a_util::result::Result read(size_t start_bit, size_t bit_length, T* value,
|
||||
Endianess endianess = get_platform_endianess())
|
||||
{
|
||||
// Check if in range
|
||||
a_util::result::Result result_code = checkForInvalidArguments(start_bit, bit_length, sizeof(T));
|
||||
if (result_code != a_util::result::SUCCESS)
|
||||
{
|
||||
return result_code;
|
||||
}
|
||||
|
||||
// Call template function
|
||||
detail::Converter<T, std::is_signed<T>::value,
|
||||
std::is_floating_point<T>::value>
|
||||
::read(_buffer, start_bit, bit_length, value, endianess);
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value to bitfield. Value can be of type tFloat or an unsigned or signed integer.
|
||||
*
|
||||
* ....|...*****|********|**......|.... Buffer (index 0 on the right end side)
|
||||
* |_______________|
|
||||
* bit_length ^
|
||||
* |
|
||||
* start_bit
|
||||
*
|
||||
* @param [in] start_bit Bit position to start writing to. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to write.
|
||||
* @param [out] value Value to write to the bitfield.
|
||||
* @param [in] endianess Parameter describing the endianess of the bitfield to write to.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
template<typename T>
|
||||
a_util::result::Result write(size_t start_bit, size_t bit_length, T value,
|
||||
Endianess endianess = get_platform_endianess())
|
||||
{
|
||||
// Check if in range
|
||||
a_util::result::Result result_code = checkForInvalidArguments(start_bit, bit_length, sizeof(T));
|
||||
if (result_code != a_util::result::SUCCESS)
|
||||
{
|
||||
return result_code;
|
||||
}
|
||||
|
||||
// Call template function
|
||||
detail::Converter<T, std::is_signed<T>::value,
|
||||
std::is_floating_point<T>::value>
|
||||
::write(_buffer, start_bit, bit_length, value, endianess);
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
private:
|
||||
/// internal buffer
|
||||
uint8_t *_buffer;
|
||||
/// size of internal buffer in bytes
|
||||
size_t _buffer_bytes;
|
||||
/// size of internal buffer in bits
|
||||
size_t _buffer_bits;
|
||||
|
||||
/**
|
||||
* Check if the parameters for the reading and writing access are valid.
|
||||
* The variable to read from or into might be too small and the accessed region of the memory buffer
|
||||
* might be out of range.
|
||||
*
|
||||
* @param [in] start_bit Bit position to start reading from. The least significant bit
|
||||
* has the index 0.
|
||||
* @param [in] bit_length Number of bits to read.
|
||||
* @param [in] size_variable Size of the variable to read into or write from.
|
||||
*
|
||||
* @return Returns a standard result code.
|
||||
*/
|
||||
a_util::result::Result checkForInvalidArguments(size_t start_bit, size_t bit_length, size_t size_variable)
|
||||
{
|
||||
if (!_buffer)
|
||||
{
|
||||
return ERR_POINTER;
|
||||
}
|
||||
|
||||
// Check invalid starting point
|
||||
if (start_bit >= _buffer_bits)
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Check out of buffer bounds or length < 1
|
||||
if ((bit_length < 1)
|
||||
|| (_buffer_bits < start_bit + bit_length))
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Check variable size
|
||||
if (size_variable * 8 < bit_length)
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
} // namespace a_util
|
||||
|
||||
#endif // A_UTILS_UTIL_MEMORY_BITSERIALIZER_INCLUDED
|
323
codec/codec.cpp
Normal file
323
codec/codec.cpp
Normal file
|
@ -0,0 +1,323 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#include "codec.h"
|
||||
|
||||
#include "a_util/result/error_def.h"
|
||||
#include "a_util/logging.h"
|
||||
#include "legacy_error_macros.h"
|
||||
#include "struct_layout.h"
|
||||
#include "static_codec.h"
|
||||
#include "element_accessor.h"
|
||||
#include "access_element.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-5, ERR_INVALID_ARG)
|
||||
_MAKE_RESULT(-10, ERR_INVALID_INDEX)
|
||||
|
||||
static inline void BitToBytes(size_t& size)
|
||||
{
|
||||
if (size % 8)
|
||||
{
|
||||
size = size/ 8 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size /= 8;
|
||||
}
|
||||
}
|
||||
|
||||
Decoder::Decoder(const Decoder& oDecoder, const void* pData, size_t nDataSize,
|
||||
DataRepresentation eRep):
|
||||
StaticDecoder(oDecoder._layout, pData, nDataSize, eRep),
|
||||
_dynamic_elements(oDecoder._dynamic_elements),
|
||||
_buffer_sizes(oDecoder._buffer_sizes)
|
||||
{
|
||||
}
|
||||
|
||||
Decoder::Decoder(a_util::memory::shared_ptr<const StructLayout> pLayout, const void* pData, size_t nDataSize,
|
||||
DataRepresentation eRep):
|
||||
StaticDecoder(pLayout, pData, nDataSize, eRep),
|
||||
_buffer_sizes(pLayout->getStaticBufferBitSizes())
|
||||
{
|
||||
if (_layout->hasDynamicElements())
|
||||
{
|
||||
a_util::result::Result oResult = calculateDynamicElements();
|
||||
if (isFailed(oResult))
|
||||
{
|
||||
LOG_ERROR("Failed to calculate dynamic elements");
|
||||
}
|
||||
}
|
||||
|
||||
BitToBytes(_buffer_sizes.deserialized);
|
||||
BitToBytes(_buffer_sizes.serialized);
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::isValid() const
|
||||
{
|
||||
RETURN_IF_FAILED(_layout->isValid());
|
||||
if (_data_size < getBufferSize(getRepresentation()))
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::calculateDynamicElements()
|
||||
{
|
||||
_dynamic_elements.reset(new std::vector<StructLayoutElement>());
|
||||
|
||||
for (std::vector<DynamicStructLayoutElement>::const_iterator
|
||||
itDynamicElement = _layout->getDynamicElements().begin();
|
||||
itDynamicElement != _layout->getDynamicElements().end(); ++ itDynamicElement)
|
||||
{
|
||||
RETURN_IF_FAILED(addDynamicElements(*itDynamicElement, _buffer_sizes, ""));
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
void Decoder::moveToAlignment(size_t& bit_offset, size_t alignment)
|
||||
{
|
||||
size_t nBitRest = bit_offset % 8;
|
||||
if (nBitRest)
|
||||
{
|
||||
bit_offset += 8 - nBitRest;
|
||||
}
|
||||
|
||||
size_t nByteOffset = bit_offset / 8;
|
||||
size_t nRest = nByteOffset % alignment;
|
||||
if (nRest)
|
||||
{
|
||||
bit_offset += (alignment - nRest) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::addDynamicElements(const DynamicStructLayoutElement& sDynamicElement,
|
||||
Offsets& sOverallOffsets,
|
||||
const std::string& strPrefix)
|
||||
{
|
||||
moveToAlignment(sOverallOffsets.deserialized, sDynamicElement.alignment);
|
||||
|
||||
if (sDynamicElement.isAlignmentElement())
|
||||
{
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::variant::Variant oArraySize((uint64_t)1);
|
||||
bool bIsArray = sDynamicElement.isDynamicArray();
|
||||
if (bIsArray)
|
||||
{
|
||||
oArraySize = access_element::get_value(*this,
|
||||
strPrefix + sDynamicElement.size_element_name);
|
||||
}
|
||||
size_t nArraySize = static_cast<size_t>(oArraySize.asUInt64());
|
||||
|
||||
for (size_t nArrayIndex = 0; nArrayIndex < nArraySize; ++nArrayIndex)
|
||||
{
|
||||
RETURN_IF_FAILED(addDynamicElement(sDynamicElement,
|
||||
bIsArray ? a_util::strings::format("[%d]", nArrayIndex) : "",
|
||||
sOverallOffsets, strPrefix));
|
||||
}
|
||||
|
||||
moveToAlignment(sOverallOffsets.deserialized, sDynamicElement.alignment);
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::addDynamicElement(const DynamicStructLayoutElement& sDynamicElement,
|
||||
const std::string& strArrayIndex,
|
||||
Offsets& sOverallOffsets,
|
||||
const std::string& strPrefix)
|
||||
{
|
||||
RETURN_IF_FAILED(addStaticStructElements(sDynamicElement, strArrayIndex, sOverallOffsets, strPrefix));
|
||||
RETURN_IF_FAILED(addDynamicStructElements(sDynamicElement, strArrayIndex, sOverallOffsets, strPrefix));
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::addStaticStructElements(const DynamicStructLayoutElement& sDynamicElement,
|
||||
const std::string& strArrayIndex,
|
||||
Offsets& nOverallBitOffset,
|
||||
const std::string& strPrefix)
|
||||
{
|
||||
Offsets sStartOffsets = nOverallBitOffset;
|
||||
for (std::vector<StructLayoutElement>::const_iterator itStaticElement = sDynamicElement.static_elements.begin();
|
||||
itStaticElement != sDynamicElement.static_elements.end(); ++itStaticElement)
|
||||
{
|
||||
StructLayoutElement sElement = *itStaticElement;
|
||||
sElement.deserialized.bit_offset += sStartOffsets.deserialized;
|
||||
sElement.serialized.bit_offset += sStartOffsets.serialized;
|
||||
nOverallBitOffset.deserialized = sElement.deserialized.bit_offset + sElement.deserialized.bit_size;
|
||||
nOverallBitOffset.serialized = sElement.serialized.bit_offset + sElement.serialized.bit_size;
|
||||
if (!sElement.name.empty())
|
||||
{
|
||||
sElement.name = a_util::strings::format("%s%s%s.%s", strPrefix.c_str(),
|
||||
sDynamicElement.name.c_str(),
|
||||
strArrayIndex.c_str(),
|
||||
itStaticElement->name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// not part of a struct, just a plain array element
|
||||
sElement.name = a_util::strings::format("%s%s%s", strPrefix.c_str(),
|
||||
sDynamicElement.name.c_str(),
|
||||
strArrayIndex.c_str());
|
||||
}
|
||||
RETURN_IF_FAILED(addDynamicStructElement(sElement));
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::addDynamicStructElements(const DynamicStructLayoutElement& sDynamicElement,
|
||||
const std::string& strArrayIndex,
|
||||
Offsets& sOverallOffsets,
|
||||
const std::string& strPrefix)
|
||||
{
|
||||
std::string strChildPrefix = a_util::strings::format("%s%s%s.", strPrefix.c_str(),
|
||||
sDynamicElement.name.c_str(),
|
||||
strArrayIndex.c_str());
|
||||
for (std::vector<DynamicStructLayoutElement>::const_iterator
|
||||
itDynamicChildElement = sDynamicElement.dynamic_elements.begin();
|
||||
itDynamicChildElement != sDynamicElement.dynamic_elements.end();
|
||||
++itDynamicChildElement)
|
||||
{
|
||||
RETURN_IF_FAILED(addDynamicElements(*itDynamicChildElement, sOverallOffsets, strChildPrefix));
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result Decoder::addDynamicStructElement(const StructLayoutElement& sElement)
|
||||
{
|
||||
const Position& sPos = _element_accessor->getRepresentation() == deserialized ?
|
||||
sElement.deserialized : sElement.serialized;
|
||||
if (sPos.bit_offset + sPos.bit_size > _data_size * 8)
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
_dynamic_elements->push_back(sElement);
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
size_t Decoder::getElementCount() const
|
||||
{
|
||||
if (_dynamic_elements)
|
||||
{
|
||||
return _layout->getStaticElements().size() + _dynamic_elements->size();
|
||||
}
|
||||
|
||||
return _layout->getStaticElements().size();
|
||||
}
|
||||
|
||||
size_t Decoder::getBufferSize(DataRepresentation eRep) const
|
||||
{
|
||||
return eRep == deserialized ?
|
||||
_buffer_sizes.deserialized :
|
||||
_buffer_sizes.serialized;
|
||||
}
|
||||
|
||||
Codec Decoder::makeCodecFor(void* pData, size_t nDataSize, DataRepresentation eRep) const
|
||||
{
|
||||
return Codec(*this, pData, nDataSize, eRep);
|
||||
}
|
||||
|
||||
const StructLayoutElement* Decoder::getLayoutElement(size_t nIndex) const
|
||||
{
|
||||
const StructLayoutElement* pElement = NULL;
|
||||
size_t nStaticElementCount = _layout->getStaticElements().size();
|
||||
if (nIndex < nStaticElementCount)
|
||||
{
|
||||
pElement = &_layout->getStaticElements()[nIndex];
|
||||
}
|
||||
else if (_dynamic_elements &&
|
||||
nIndex - nStaticElementCount < _dynamic_elements->size())
|
||||
{
|
||||
pElement = &(*_dynamic_elements)[nIndex - nStaticElementCount];
|
||||
}
|
||||
|
||||
return pElement;
|
||||
}
|
||||
|
||||
Codec::Codec(a_util::memory::shared_ptr<const StructLayout> pLayout, void* pData, size_t nDataSize,
|
||||
DataRepresentation eRep):
|
||||
Decoder(pLayout, pData, nDataSize, eRep)
|
||||
{
|
||||
}
|
||||
|
||||
Codec::Codec(const Decoder& oDecoder, void* pData, size_t nDataSize, DataRepresentation eRep):
|
||||
Decoder(oDecoder, pData, nDataSize, eRep)
|
||||
{
|
||||
}
|
||||
|
||||
a_util::result::Result Codec::setElementValue(size_t nIndex, const void* pValue)
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
return _element_accessor->setValue(*pElement,
|
||||
const_cast<void*>(_data),
|
||||
_data_size,
|
||||
pValue);
|
||||
}
|
||||
|
||||
a_util::result::Result Codec::setElementValue(size_t nIndex, const a_util::variant::Variant& oValue)
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
return _element_accessor->setValue(*pElement, const_cast<void*>(_data),
|
||||
_data_size, oValue);
|
||||
}
|
||||
|
||||
void* Codec::getElementAddress(size_t nIndex)
|
||||
{
|
||||
return const_cast<void*>(StaticDecoder::getElementAddress(nIndex));
|
||||
}
|
||||
|
||||
a_util::result::Result Codec::setConstants()
|
||||
{
|
||||
if (_layout->hasEnums())
|
||||
{
|
||||
size_t nElementCount = getElementCount();
|
||||
for (size_t nElement = 0; nElement < nElementCount; ++nElement)
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nElement);
|
||||
if (pElement->constant)
|
||||
{
|
||||
RETURN_IF_FAILED(_element_accessor->setValue(*pElement, const_cast<void*>(_data),
|
||||
_data_size, *pElement->constant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
161
codec/codec.h
Normal file
161
codec/codec.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef DDL_CODEC_CLASS_HEADER
|
||||
#define DDL_CODEC_CLASS_HEADER
|
||||
|
||||
#include "a_util/result.h"
|
||||
|
||||
#include "static_codec.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
class Codec;
|
||||
|
||||
/**
|
||||
* Decoder for dynamic structures defined by a DDL definition.
|
||||
*/
|
||||
class Decoder: public StaticDecoder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @copydoc StaticDecoder::isValid
|
||||
*/
|
||||
virtual a_util::result::Result isValid() const;
|
||||
|
||||
/**
|
||||
* @copydoc StaticDecoder::getElementCount
|
||||
*/
|
||||
virtual size_t getElementCount() const;
|
||||
|
||||
/**
|
||||
* @param[in] rep The data representation for which the buffer size should be returned.
|
||||
* @return The size of the structure in the requested data representation.
|
||||
*/
|
||||
size_t getBufferSize(DataRepresentation rep = deserialized) const;
|
||||
|
||||
/**
|
||||
* Create a new codec with the current dynamic structure layout for a new data buffer.
|
||||
* @param[in] data The pointer to the new raw data.
|
||||
* @param[in] data_size The size of the new raw data.
|
||||
* @param[in] rep The representation that the data should be encoded in.
|
||||
* @return A codec.
|
||||
*/
|
||||
Codec makeCodecFor(void* data, size_t data_size, DataRepresentation rep) const;
|
||||
|
||||
protected:
|
||||
friend class CodecFactory;
|
||||
/// For internal use only. @internal
|
||||
Decoder(a_util::memory::shared_ptr<const StructLayout> layout, const void* data, size_t data_size,
|
||||
DataRepresentation rep);
|
||||
/// For internal use only. @internal
|
||||
Decoder(const Decoder& decoder, const void* data, size_t data_size,
|
||||
DataRepresentation rep);
|
||||
/// For internal use only. @internal
|
||||
virtual const StructLayoutElement* getLayoutElement(size_t index) const;
|
||||
|
||||
private:
|
||||
/// For internal use only. @internal
|
||||
a_util::result::Result calculateDynamicElements();
|
||||
/// For internal use only. @internal
|
||||
a_util::result::Result addDynamicElements(const DynamicStructLayoutElement& dynamic_element,
|
||||
Offsets& overall_offsets,
|
||||
const std::string& prefix);
|
||||
/// For internal use only. @internal
|
||||
a_util::result::Result addDynamicElement(const DynamicStructLayoutElement& dynamic_element,
|
||||
const std::string& array_index,
|
||||
Offsets& overall_offsets,
|
||||
const std::string& prefix);
|
||||
/// For internal use only. @internal
|
||||
a_util::result::Result addStaticStructElements(const DynamicStructLayoutElement& dynamic_element,
|
||||
const std::string& array_index,
|
||||
Offsets& overall_offsets,
|
||||
const std::string& prefix);
|
||||
/// For internal use only. @internal
|
||||
a_util::result::Result addDynamicStructElements(const DynamicStructLayoutElement& dynamic_element,
|
||||
const std::string& array_index,
|
||||
Offsets& overall_offsets,
|
||||
const std::string& prefix);
|
||||
/// For internal use only. @internal
|
||||
a_util::result::Result addDynamicStructElement(const StructLayoutElement& element);
|
||||
/// For internal use only. @internal
|
||||
void moveToAlignment(size_t& bit_offset, size_t alignment);
|
||||
|
||||
protected:
|
||||
/// For internal use only. @internal
|
||||
a_util::memory::shared_ptr<std::vector<StructLayoutElement> > _dynamic_elements;
|
||||
/// For internal use only. @internal
|
||||
Offsets _buffer_sizes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decoder for dynamic structures defined by a DDL definition.
|
||||
* Currently the amount of dynamic elements is determined during construction
|
||||
* only (by the current values in the structure).
|
||||
*/
|
||||
class Codec: public Decoder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Sets the current value of the given element by copying its data
|
||||
* from the passed-in location.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[in] value The location where the data should be copied from.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result setElementValue(size_t index, const void* value);
|
||||
|
||||
/**
|
||||
* Sets the current value of the given element to the given value.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[in] value The value.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result setElementValue(size_t index, const a_util::variant::Variant& value);
|
||||
|
||||
/**
|
||||
* @param[in] index The index of the element.
|
||||
* @return A pointer to the element or NULL in case of an error.
|
||||
*/
|
||||
void* getElementAddress(size_t index);
|
||||
using StaticDecoder::getElementAddress;
|
||||
|
||||
/**
|
||||
* Sets all elements to their constant values defined in the DDL.
|
||||
* @return Standard result.
|
||||
*/
|
||||
a_util::result::Result setConstants();
|
||||
|
||||
protected:
|
||||
friend class CodecFactory;
|
||||
friend class Decoder;
|
||||
/// For internal use only. @internal
|
||||
Codec(a_util::memory::shared_ptr<const StructLayout> layout, void* data, size_t data_size,
|
||||
DataRepresentation rep);
|
||||
/// For internal use only. @internal
|
||||
Codec(const Decoder& decoder, void* data, size_t data_size,
|
||||
DataRepresentation rep);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
29
codec/codec.sources
Normal file
29
codec/codec.sources
Normal file
|
@ -0,0 +1,29 @@
|
|||
set(CODEC_DIR codec)
|
||||
|
||||
set(CODEC_H_PUBLIC
|
||||
${CODEC_DIR}/pkg_codec.h
|
||||
${CODEC_DIR}/struct_element.h
|
||||
${CODEC_DIR}/access_element.h
|
||||
${CODEC_DIR}/static_codec.h
|
||||
${CODEC_DIR}/codec.h
|
||||
${CODEC_DIR}/codec_factory.h
|
||||
${CODEC_DIR}/bitserializer.h
|
||||
)
|
||||
set(CODEC_H
|
||||
${CODEC_H_PUBLIC}
|
||||
${CODEC_DIR}/struct_layout.h
|
||||
${CODEC_DIR}/element_accessor.h
|
||||
)
|
||||
|
||||
set(CODEC_CPP
|
||||
${CODEC_DIR}/struct_layout.cpp
|
||||
${CODEC_DIR}/element_accessor.cpp
|
||||
${CODEC_DIR}/static_codec.cpp
|
||||
${CODEC_DIR}/codec.cpp
|
||||
${CODEC_DIR}/codec_factory.cpp
|
||||
${CODEC_DIR}/bitserializer.cpp
|
||||
)
|
||||
|
||||
set(CODEC_INSTALL ${CODEC_H_PUBLIC})
|
||||
source_group(${CODEC_DIR} FILES ${CODEC_H} ${CODEC_CPP})
|
||||
|
117
codec/codec_factory.cpp
Normal file
117
codec/codec_factory.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#include "struct_layout.h"
|
||||
#include "codec_factory.h"
|
||||
|
||||
#include "ddlrepresentation/ddl_error.h"
|
||||
#include "ddlrepresentation/ddldescription.h"
|
||||
#include "ddlrepresentation/ddlimporter.h"
|
||||
#include "ddlrepresentation/ddlversion.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-10, ERR_INVALID_INDEX)
|
||||
_MAKE_RESULT(-20, ERR_NOT_FOUND)
|
||||
_MAKE_RESULT(-37, ERR_NOT_INITIALIZED)
|
||||
|
||||
static a_util::result::Result getDDL(const char* strMediaDescription,
|
||||
a_util::memory::unique_ptr<DDLDescription>& pDDL)
|
||||
{
|
||||
DDLVersion version_helper = DDLVersion::ddl_version_current;
|
||||
|
||||
ddl::DDLImporter oImporter;
|
||||
a_util::memory::unique_ptr<ddl::DDLDescription> pDefaultDescription(
|
||||
ddl::DDLDescription::createDefault(version_helper, 4));
|
||||
|
||||
RETURN_DDLERROR_IF_FAILED_DESC(oImporter.setXML(strMediaDescription), oImporter.getErrorDesc());
|
||||
RETURN_DDLERROR_IF_FAILED_DESC(oImporter.createPartial(pDefaultDescription.get(),
|
||||
version_helper),
|
||||
oImporter.getErrorDesc());
|
||||
|
||||
pDDL.reset(oImporter.getDDL());
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
CodecFactory::CodecFactory():
|
||||
_layout(new StructLayout()),
|
||||
_constructor_result(ERR_NOT_INITIALIZED)
|
||||
{
|
||||
}
|
||||
|
||||
CodecFactory::CodecFactory(const char* strStructName, const char* strMediaDescription)
|
||||
{
|
||||
a_util::memory::unique_ptr<DDLDescription> pDDL;
|
||||
_constructor_result = getDDL(strMediaDescription, pDDL);
|
||||
if(isOk(_constructor_result))
|
||||
{
|
||||
DDLComplex* pStruct = pDDL->getStructByName(strStructName);
|
||||
if (pStruct)
|
||||
{
|
||||
_layout.reset(new StructLayout(pStruct));
|
||||
_constructor_result = _layout->isValid();
|
||||
}
|
||||
else
|
||||
{
|
||||
_constructor_result = ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_layout)
|
||||
{
|
||||
_layout.reset(new StructLayout());
|
||||
}
|
||||
}
|
||||
|
||||
CodecFactory::CodecFactory(const DDLComplex* pStruct):
|
||||
_layout(new StructLayout(pStruct))
|
||||
{
|
||||
_constructor_result = _layout->isValid();
|
||||
}
|
||||
|
||||
a_util::result::Result CodecFactory::isValid() const
|
||||
{
|
||||
return _constructor_result;
|
||||
}
|
||||
|
||||
size_t CodecFactory::getStaticElementCount() const
|
||||
{
|
||||
return _layout->getStaticElements().size();
|
||||
}
|
||||
|
||||
a_util::result::Result CodecFactory::getStaticElement(size_t nIndex, const StructElement*& pElement) const
|
||||
{
|
||||
if (nIndex >= getStaticElementCount())
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
pElement = &_layout->getStaticElements()[nIndex];
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
size_t CodecFactory::getStaticBufferSize(DataRepresentation eRep) const
|
||||
{
|
||||
return _layout->getStaticBufferSize(eRep);
|
||||
}
|
||||
|
||||
|
||||
}
|
147
codec/codec_factory.h
Normal file
147
codec/codec_factory.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef DDL_CODEC_FACTORY_CLASS_HEADER
|
||||
#define DDL_CODEC_FACTORY_CLASS_HEADER
|
||||
|
||||
#include "codec.h"
|
||||
|
||||
#include "ddlrepresentation/ddlcomplex.h"
|
||||
#include "struct_element.h"
|
||||
#include "static_codec.h"
|
||||
|
||||
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
/**
|
||||
* Factory class for ddl codecs.
|
||||
*/
|
||||
class CodecFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Empty constructor. This exists to enable uninitialized member variables of this type
|
||||
* that are move-assigned later on.
|
||||
*/
|
||||
CodecFactory();
|
||||
|
||||
/**
|
||||
* Constructor that take a DDL string for initialization.
|
||||
* @param[in] struct_name The name of the struct for which codecs should be generated.
|
||||
* @param[in] media_description The DDL description.
|
||||
*/
|
||||
CodecFactory(const char* struct_name,
|
||||
const char* media_description);
|
||||
|
||||
/**
|
||||
* Constructor that uses an OO-DDL struct for initialization.
|
||||
* @param[in] ddl_struct The struct definition.
|
||||
*/
|
||||
CodecFactory(const DDLComplex* ddl_struct);
|
||||
|
||||
/**
|
||||
* Check if the factory is in a valid state.
|
||||
* @return Any errors during construction.
|
||||
*/
|
||||
a_util::result::Result isValid() const;
|
||||
|
||||
/**
|
||||
* Creates a static decoder for the given data.
|
||||
* @param[in] data The pointer to the raw data.
|
||||
* @param[in] data_size The size of the raw data.
|
||||
* @param[in] rep The representation that the data is encoded in.
|
||||
* @return a static decoder.
|
||||
*/
|
||||
inline StaticDecoder makeStaticDecoderFor(const void* data, size_t data_size,
|
||||
DataRepresentation rep = deserialized) const
|
||||
{
|
||||
return StaticDecoder(_layout, data, data_size, rep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a static codec for the given data.
|
||||
* @param[in] data The pointer to the raw data.
|
||||
* @param[in] data_size The size of the raw data.
|
||||
* @param[in] rep The representation that the data is encoded in.
|
||||
* @return a static codec.
|
||||
*/
|
||||
inline StaticCodec makeStaticCodecFor(void* data, size_t data_size,
|
||||
DataRepresentation rep = deserialized) const
|
||||
{
|
||||
return StaticCodec(_layout, data, data_size, rep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a decoder for the given data.
|
||||
* @param[in] data The pointer to the raw data.
|
||||
* @param[in] data_size The size of the raw data.
|
||||
* @param[in] rep The representation that the data is encoded in.
|
||||
* @return a decoder.
|
||||
*/
|
||||
inline Decoder makeDecoderFor(const void* data, size_t data_size,
|
||||
DataRepresentation rep = deserialized) const
|
||||
{
|
||||
return Decoder(_layout, data, data_size, rep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a codec for the given data.
|
||||
* @param[in] data The pointer to the raw data.
|
||||
* @param[in] data_size The size of the raw data.
|
||||
* @param[in] rep The representation that the data is encoded in.
|
||||
* @return a codec.
|
||||
*/
|
||||
inline Codec makeCodecFor(void* data, size_t data_size,
|
||||
DataRepresentation rep = deserialized) const
|
||||
{
|
||||
return Codec(_layout, data, data_size, rep);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The amount of static elements contained in the handled structure.
|
||||
*/
|
||||
size_t getStaticElementCount() const;
|
||||
|
||||
/**
|
||||
* Access information about an element.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[out] element Pointer that will be updated to point to the element information.
|
||||
* @retval ERR_INVALID_INDEX Invalid index.
|
||||
*/
|
||||
a_util::result::Result getStaticElement(size_t index, const StructElement*& element) const;
|
||||
|
||||
/**
|
||||
* @param[in] rep The data representation for which the buffer size should be returned.
|
||||
* @return The size of the structure in the requested data representation.
|
||||
*/
|
||||
size_t getStaticBufferSize(DataRepresentation rep = deserialized) const;
|
||||
|
||||
private:
|
||||
/// For internal use only. @internal The struct layout.
|
||||
a_util::memory::shared_ptr<const StructLayout> _layout;
|
||||
/// For internal use only. @internal The constructor result.
|
||||
a_util::result::Result _constructor_result;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
228
codec/element_accessor.cpp
Normal file
228
codec/element_accessor.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "a_util/result/error_def.h"
|
||||
#include "a_util/variant.h"
|
||||
#include "a_util/memory.h"
|
||||
#include "element_accessor.h"
|
||||
#include "legacy_error_macros.h"
|
||||
#include "bitserializer.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-5, ERR_INVALID_ARG)
|
||||
_MAKE_RESULT(-19, ERR_NOT_SUPPORTED)
|
||||
|
||||
template <typename T>
|
||||
a_util::result::Result get_typed_element_value(const StructLayoutElement& sElement, const void* pData,
|
||||
size_t nDataSize, a_util::variant::Variant& oValue,
|
||||
const ElementAccessor& oAccessor)
|
||||
{
|
||||
T xValue;
|
||||
RETURN_IF_FAILED(oAccessor.getValue(sElement, pData, nDataSize, &xValue));
|
||||
oValue = xValue;
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
#define GET_CASE_TYPE(__variant_type, __data_type) \
|
||||
case a_util::variant::__variant_type: \
|
||||
{ \
|
||||
return get_typed_element_value<__data_type>(sElement, pData, nDataSize, oValue, *this); \
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
a_util::result::Result set_typed_element_value(const StructLayoutElement& sElement, void* pData,
|
||||
size_t nDataSize, const a_util::variant::Variant& oValue,
|
||||
const ElementAccessor& oAccessor)
|
||||
{
|
||||
T xHelper = oValue;
|
||||
return oAccessor.setValue(sElement, pData, nDataSize, &xHelper);
|
||||
}
|
||||
|
||||
#define SET_CASE_TYPE(__variant_type, __data_type) \
|
||||
case a_util::variant::__variant_type: \
|
||||
{ \
|
||||
return set_typed_element_value<__data_type>(sElement, pData, nDataSize, oValue, *this); \
|
||||
}
|
||||
|
||||
a_util::result::Result ElementAccessor::getValue(const StructLayoutElement& sElement, const void* pData,
|
||||
size_t nDataSize, a_util::variant::Variant& oValue) const
|
||||
{
|
||||
switch(sElement.type)
|
||||
{
|
||||
GET_CASE_TYPE(VT_Bool, bool)
|
||||
GET_CASE_TYPE(VT_Int8, int8_t)
|
||||
GET_CASE_TYPE(VT_UInt8, uint8_t)
|
||||
GET_CASE_TYPE(VT_Int16, int16_t)
|
||||
GET_CASE_TYPE(VT_UInt16, uint16_t)
|
||||
GET_CASE_TYPE(VT_Int32, int32_t)
|
||||
GET_CASE_TYPE(VT_UInt32, uint32_t)
|
||||
GET_CASE_TYPE(VT_Int64, int64_t)
|
||||
GET_CASE_TYPE(VT_UInt64, uint64_t)
|
||||
GET_CASE_TYPE(VT_Float32, float)
|
||||
GET_CASE_TYPE(VT_Float64, double)
|
||||
default: return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
a_util::result::Result ElementAccessor::setValue(const StructLayoutElement& sElement, void* pData,
|
||||
size_t nDataSize, const a_util::variant::Variant& oValue) const
|
||||
{
|
||||
switch(sElement.type)
|
||||
{
|
||||
SET_CASE_TYPE(VT_Bool, bool)
|
||||
SET_CASE_TYPE(VT_Int8, int8_t)
|
||||
SET_CASE_TYPE(VT_UInt8, uint8_t)
|
||||
SET_CASE_TYPE(VT_Int16, int16_t)
|
||||
SET_CASE_TYPE(VT_UInt16, uint16_t)
|
||||
SET_CASE_TYPE(VT_Int32, int32_t)
|
||||
SET_CASE_TYPE(VT_UInt32, uint32_t)
|
||||
SET_CASE_TYPE(VT_Int64, int64_t)
|
||||
SET_CASE_TYPE(VT_UInt64, uint64_t)
|
||||
SET_CASE_TYPE(VT_Float32, float)
|
||||
SET_CASE_TYPE(VT_Float64, double)
|
||||
default: return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
a_util::result::Result DeserializedAccessor::getValue(const StructLayoutElement& sElement, const void* pData,
|
||||
size_t nDataSize, void* pElementValue) const
|
||||
{
|
||||
assert(sElement.deserialized.bit_offset % 8 == 0);
|
||||
assert(sElement.deserialized.bit_size % 8 == 0);
|
||||
size_t nByteOffset = sElement.deserialized.bit_offset / 8;
|
||||
size_t nByteSize = sElement.deserialized.bit_size / 8;
|
||||
if (nDataSize < nByteOffset + nByteSize)
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
a_util::memory::copy(pElementValue, nByteSize,
|
||||
reinterpret_cast<const void*>(static_cast<const uint8_t*>(pData) + nByteOffset),
|
||||
nByteSize);
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result DeserializedAccessor::setValue(const StructLayoutElement& sElement, void* pData,
|
||||
size_t nDataSize, const void* pElementValue) const
|
||||
{
|
||||
assert(sElement.deserialized.bit_offset % 8 == 0);
|
||||
assert(sElement.deserialized.bit_size % 8 == 0);
|
||||
size_t nByteOffset = sElement.deserialized.bit_offset / 8;
|
||||
size_t nByteSize = sElement.deserialized.bit_size / 8;
|
||||
if (nDataSize < nByteOffset + nByteSize)
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
a_util::memory::copy(static_cast<uint8_t*>(pData) + nByteOffset, nByteSize,
|
||||
pElementValue,
|
||||
nByteSize);
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
const ElementAccessor& DeserializedAccessor::getInstance()
|
||||
{
|
||||
static DeserializedAccessor oInstance;
|
||||
return oInstance;
|
||||
}
|
||||
|
||||
const ElementAccessor& SerializedAccessor::getInstance()
|
||||
{
|
||||
static SerializedAccessor oInstance;
|
||||
return oInstance;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
a_util::result::Result read_typed_bits(const StructLayoutElement& sElement, const void* pData,
|
||||
size_t nDataSize, void* pElementValue)
|
||||
{
|
||||
a_util::memory::BitSerializer oHelper(const_cast<void*>(pData), nDataSize);
|
||||
return oHelper.read<T>(sElement.serialized.bit_offset, sElement.serialized.bit_size,
|
||||
reinterpret_cast<T*>(pElementValue),
|
||||
(a_util::memory::Endianess)sElement.byte_order);
|
||||
}
|
||||
|
||||
#define GET_CASE_TYPE_SER(__variant_type, __data_type) \
|
||||
case a_util::variant::__variant_type: \
|
||||
{ \
|
||||
return read_typed_bits<__data_type>(sElement, pData, nDataSize, pElementValue); \
|
||||
}
|
||||
|
||||
a_util::result::Result SerializedAccessor::getValue(const StructLayoutElement& sElement, const void* pData,
|
||||
size_t nDataSize, void* pElementValue) const
|
||||
{
|
||||
switch(sElement.type)
|
||||
{
|
||||
GET_CASE_TYPE_SER(VT_Bool, bool)
|
||||
GET_CASE_TYPE_SER(VT_Int8, int8_t)
|
||||
GET_CASE_TYPE_SER(VT_UInt8, uint8_t)
|
||||
GET_CASE_TYPE_SER(VT_Int16, int16_t)
|
||||
GET_CASE_TYPE_SER(VT_UInt16, uint16_t)
|
||||
GET_CASE_TYPE_SER(VT_Int32, int32_t)
|
||||
GET_CASE_TYPE_SER(VT_UInt32, uint32_t)
|
||||
GET_CASE_TYPE_SER(VT_Int64, int64_t)
|
||||
GET_CASE_TYPE_SER(VT_UInt64, uint64_t)
|
||||
GET_CASE_TYPE_SER(VT_Float32, float)
|
||||
GET_CASE_TYPE_SER(VT_Float64, double)
|
||||
default: return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
a_util::result::Result write_typed_bits(const StructLayoutElement& sElement, void* pData,
|
||||
size_t nDataSize, const void* pElementValue)
|
||||
{
|
||||
a_util::memory::BitSerializer oHelper(pData, nDataSize);
|
||||
return oHelper.write<T>(sElement.serialized.bit_offset, sElement.serialized.bit_size,
|
||||
*reinterpret_cast<const T*>(pElementValue),
|
||||
(a_util::memory::Endianess)sElement.byte_order);
|
||||
}
|
||||
|
||||
#define SET_CASE_TYPE_SER(__variant_type, __data_type) \
|
||||
case a_util::variant::__variant_type: \
|
||||
{ \
|
||||
return write_typed_bits<__data_type>(sElement, pData, nDataSize, pElementValue); \
|
||||
}
|
||||
|
||||
a_util::result::Result SerializedAccessor::setValue(const StructLayoutElement& sElement, void* pData,
|
||||
size_t nDataSize, const void* pElementValue) const
|
||||
{
|
||||
switch(sElement.type)
|
||||
{
|
||||
SET_CASE_TYPE_SER(VT_Bool, bool)
|
||||
SET_CASE_TYPE_SER(VT_Int8, int8_t)
|
||||
SET_CASE_TYPE_SER(VT_UInt8, uint8_t)
|
||||
SET_CASE_TYPE_SER(VT_Int16, int16_t)
|
||||
SET_CASE_TYPE_SER(VT_UInt16, uint16_t)
|
||||
SET_CASE_TYPE_SER(VT_Int32, int32_t)
|
||||
SET_CASE_TYPE_SER(VT_UInt32, uint32_t)
|
||||
SET_CASE_TYPE_SER(VT_Int64, int64_t)
|
||||
SET_CASE_TYPE_SER(VT_UInt64, uint64_t)
|
||||
SET_CASE_TYPE_SER(VT_Float32, float)
|
||||
SET_CASE_TYPE_SER(VT_Float64, double)
|
||||
default: return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
83
codec/element_accessor.h
Normal file
83
codec/element_accessor.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef DDL_STRUCT_ELEMENT_ACCESS_PRIVATE_CLASS_HEADER
|
||||
#define DDL_STRUCT_ELEMENT_ACCESS_PRIVATE_CLASS_HEADER
|
||||
|
||||
#include "a_util/result.h"
|
||||
#include "struct_layout.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
class ElementAccessor
|
||||
{
|
||||
public:
|
||||
virtual a_util::result::Result getValue(const StructLayoutElement& element, const void* data,
|
||||
size_t data_size, void* element_value) const = 0;
|
||||
virtual a_util::result::Result setValue(const StructLayoutElement& element, void* data,
|
||||
size_t data_size, const void* element_value) const = 0;
|
||||
|
||||
virtual DataRepresentation getRepresentation() const = 0;
|
||||
|
||||
a_util::result::Result getValue(const StructLayoutElement& element, const void* data,
|
||||
size_t data_size, a_util::variant::Variant& value) const;
|
||||
|
||||
a_util::result::Result setValue(const StructLayoutElement& element, void* data,
|
||||
size_t data_size, const a_util::variant::Variant& value) const;
|
||||
};
|
||||
|
||||
class DeserializedAccessor: public ElementAccessor
|
||||
{
|
||||
public:
|
||||
virtual a_util::result::Result getValue(const StructLayoutElement& element, const void* data,
|
||||
size_t data_size, void* element_value) const;
|
||||
virtual a_util::result::Result setValue(const StructLayoutElement& element, void* data,
|
||||
size_t data_size, const void* element_value) const;
|
||||
|
||||
virtual DataRepresentation getRepresentation() const
|
||||
{
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
static const ElementAccessor& getInstance();
|
||||
};
|
||||
|
||||
|
||||
class SerializedAccessor: public ElementAccessor
|
||||
{
|
||||
public:
|
||||
virtual a_util::result::Result getValue(const StructLayoutElement& element, const void* data,
|
||||
size_t data_size, void* element_value) const;
|
||||
virtual a_util::result::Result setValue(const StructLayoutElement& element, void* data,
|
||||
size_t data_size, const void* element_value) const;
|
||||
|
||||
virtual DataRepresentation getRepresentation() const
|
||||
{
|
||||
return serialized;
|
||||
}
|
||||
|
||||
static const ElementAccessor& getInstance();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
32
codec/pkg_codec.h
Normal file
32
codec/pkg_codec.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef _DDL_CODEC_PKG_HEADER_
|
||||
#define _DDL_CODEC_PKG_HEADER_
|
||||
|
||||
#include "struct_element.h"
|
||||
#include "static_codec.h"
|
||||
#include "codec.h"
|
||||
#include "codec_factory.h"
|
||||
#include "access_element.h"
|
||||
#include "bitserializer.h"
|
||||
|
||||
#endif
|
||||
|
198
codec/static_codec.cpp
Normal file
198
codec/static_codec.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#include "static_codec.h"
|
||||
|
||||
#include "a_util/result/error_def.h"
|
||||
#include "legacy_error_macros.h"
|
||||
#include "element_accessor.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-5, ERR_INVALID_ARG)
|
||||
_MAKE_RESULT(-10, ERR_INVALID_INDEX)
|
||||
|
||||
StaticDecoder::StaticDecoder(a_util::memory::shared_ptr<const StructLayout> pLayout,
|
||||
const void* pData, size_t nDataSize,
|
||||
DataRepresentation eRep):
|
||||
_layout(pLayout),
|
||||
_data(pData),
|
||||
_data_size(nDataSize),
|
||||
_element_accessor(eRep == deserialized ?
|
||||
&DeserializedAccessor::getInstance() :
|
||||
&SerializedAccessor::getInstance())
|
||||
{
|
||||
}
|
||||
|
||||
a_util::result::Result StaticDecoder::isValid() const
|
||||
{
|
||||
RETURN_IF_FAILED(_layout->isValid());
|
||||
if (_data_size < getStaticBufferSize(getRepresentation()))
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
size_t StaticDecoder::getElementCount() const
|
||||
{
|
||||
return _layout->getStaticElements().size();
|
||||
}
|
||||
|
||||
a_util::result::Result StaticDecoder::getElement(size_t nIndex, const StructElement*& pElement) const
|
||||
{
|
||||
pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result StaticDecoder::getElementValue(size_t nIndex, void* pValue) const
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
return _element_accessor->getValue(*pElement, _data, _data_size, pValue);
|
||||
}
|
||||
|
||||
a_util::result::Result StaticDecoder::getElementValue(size_t nIndex, a_util::variant::Variant& oValue) const
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
return _element_accessor->getValue(*pElement, _data, _data_size, oValue);
|
||||
}
|
||||
|
||||
const void* StaticDecoder::getElementAddress(size_t nIndex) const
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t nBitPos = _element_accessor->getRepresentation() == deserialized ?
|
||||
pElement->deserialized.bit_offset :
|
||||
pElement->serialized.bit_offset;
|
||||
|
||||
if (nBitPos % 8)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t bit_size = _element_accessor->getRepresentation() == deserialized ?
|
||||
pElement->deserialized.bit_size :
|
||||
pElement->serialized.bit_size;
|
||||
|
||||
if ((nBitPos / 8) + (bit_size / 8) + (bit_size % 8 ? 1 : 0) >
|
||||
_data_size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return static_cast<const uint8_t*>(_data) + (nBitPos / 8);
|
||||
}
|
||||
|
||||
const StructLayoutElement* StaticDecoder::getLayoutElement(size_t nIndex) const
|
||||
{
|
||||
const StructLayoutElement* pElement = NULL;
|
||||
if (nIndex < _layout->getStaticElements().size())
|
||||
{
|
||||
pElement = &_layout->getStaticElements()[nIndex];
|
||||
}
|
||||
|
||||
return pElement;
|
||||
}
|
||||
|
||||
size_t StaticDecoder::getStaticBufferSize(DataRepresentation eRep) const
|
||||
{
|
||||
return _layout->getStaticBufferSize(eRep);
|
||||
}
|
||||
|
||||
DataRepresentation StaticDecoder::getRepresentation() const
|
||||
{
|
||||
return _element_accessor->getRepresentation();
|
||||
}
|
||||
|
||||
StaticCodec::StaticCodec(a_util::memory::shared_ptr<const StructLayout> pLayout,
|
||||
void* pData, size_t nDataSize, DataRepresentation eRep):
|
||||
StaticDecoder(pLayout, pData, nDataSize, eRep)
|
||||
{
|
||||
}
|
||||
|
||||
a_util::result::Result StaticCodec::setElementValue(size_t nIndex, const void* pValue)
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
return _element_accessor->setValue(*pElement,
|
||||
const_cast<void*>(_data),
|
||||
_data_size,
|
||||
pValue);
|
||||
}
|
||||
|
||||
a_util::result::Result StaticCodec::setElementValue(size_t nIndex, const a_util::variant::Variant& oValue)
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nIndex);
|
||||
if (!pElement)
|
||||
{
|
||||
return ERR_INVALID_INDEX;
|
||||
}
|
||||
return _element_accessor->setValue(*pElement, const_cast<void*>(_data),
|
||||
_data_size, oValue);
|
||||
}
|
||||
|
||||
void* StaticCodec::getElementAddress(size_t nIndex)
|
||||
{
|
||||
return const_cast<void*>(StaticDecoder::getElementAddress(nIndex));
|
||||
}
|
||||
|
||||
a_util::result::Result StaticCodec::setConstants()
|
||||
{
|
||||
if (_layout->hasEnums())
|
||||
{
|
||||
size_t nElementCount = getElementCount();
|
||||
for (size_t nElement = 0; nElement < nElementCount; ++nElement)
|
||||
{
|
||||
const StructLayoutElement* pElement = getLayoutElement(nElement);
|
||||
if (pElement->constant)
|
||||
{
|
||||
RETURN_IF_FAILED(_element_accessor->setValue(*pElement, const_cast<void*>(_data),
|
||||
_data_size, *pElement->constant));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
}
|
181
codec/static_codec.h
Normal file
181
codec/static_codec.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef DDL_STATIC_CODEC_CLASS_HEADER
|
||||
#define DDL_STATIC_CODEC_CLASS_HEADER
|
||||
|
||||
#include "a_util/result.h"
|
||||
#include "a_util/variant.h"
|
||||
#include "a_util/memory.h"
|
||||
|
||||
#include "struct_element.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
class StructLayout;
|
||||
class ElementAccessor;
|
||||
|
||||
/**
|
||||
* Decoder for static structures defined by a DDL definition.
|
||||
*/
|
||||
class StaticDecoder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Noncopyable
|
||||
*/
|
||||
StaticDecoder(const StaticDecoder&) = delete;
|
||||
|
||||
/**
|
||||
* Noncopyable
|
||||
*/
|
||||
StaticDecoder& operator=(const StaticDecoder&) = delete;
|
||||
|
||||
/**
|
||||
* Move constructor.
|
||||
*/
|
||||
StaticDecoder(StaticDecoder&&) = default;
|
||||
|
||||
/**
|
||||
* Move assignment operator.
|
||||
*/
|
||||
StaticDecoder& operator=(StaticDecoder&&) = default;
|
||||
|
||||
/**
|
||||
* @return Whether or not the decoder is valid.
|
||||
* @retval ERR_INVALID_ARG The passed data is not large enough.
|
||||
*/
|
||||
virtual a_util::result::Result isValid() const;
|
||||
|
||||
/**
|
||||
* @return The amount of elements contained in the data structure.
|
||||
*/
|
||||
virtual size_t getElementCount() const;
|
||||
|
||||
/**
|
||||
* Access information about an element.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[out] element Pointer that will be updated to point to the element information.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result getElement(size_t index, const StructElement*& element) const;
|
||||
|
||||
/**
|
||||
* Returns the current value of the given element by copying its data
|
||||
* to the passed-in location.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[out] value The location where the value should be copied to.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result getElementValue(size_t index, void* value) const;
|
||||
|
||||
/**
|
||||
* Returns the current value of the given element as a variant.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[out] value The will be set to the current value.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result getElementValue(size_t index, a_util::variant::Variant& value) const;
|
||||
|
||||
/**
|
||||
* @param[in] index The index of the element.
|
||||
* @return A pointer to the element or NULL in case of an error.
|
||||
*/
|
||||
const void* getElementAddress(size_t index) const;
|
||||
|
||||
/**
|
||||
* @param[in] rep The data representation for which the buffer size should be returned.
|
||||
* @return The size of the structure in the requested data representation.
|
||||
*/
|
||||
size_t getStaticBufferSize(DataRepresentation rep = deserialized) const;
|
||||
|
||||
/**
|
||||
* @return The data representation which this decoder handles.
|
||||
*/
|
||||
DataRepresentation getRepresentation() const;
|
||||
|
||||
protected:
|
||||
friend class CodecFactory;
|
||||
|
||||
/// For internal use only. @internal
|
||||
StaticDecoder(a_util::memory::shared_ptr<const StructLayout> layout,
|
||||
const void* data, size_t data_size,
|
||||
DataRepresentation rep);
|
||||
/// For internal use only. @internal
|
||||
virtual const StructLayoutElement* getLayoutElement(size_t index) const;
|
||||
|
||||
protected:
|
||||
/// For internal use only. @internal
|
||||
a_util::memory::shared_ptr<const StructLayout> _layout;
|
||||
/// For internal use only. @internal
|
||||
const void* _data;
|
||||
/// For internal use only. @internal
|
||||
size_t _data_size;
|
||||
/// For internal use only. @internal
|
||||
const ElementAccessor* _element_accessor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Codec for static structures defined by a DDL definition.
|
||||
*/
|
||||
class StaticCodec: public StaticDecoder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Sets the current value of the given element by copying its data
|
||||
* from the passed-in location.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[in] value The location where the data should be copied from.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result setElementValue(size_t index, const void* value);
|
||||
|
||||
/**
|
||||
* Sets the current value of the given element to the given value.
|
||||
* @param[in] index The index of the element.
|
||||
* @param[in] value The value.
|
||||
* @retval ERR_INVALID_INDEX Invalid element index.
|
||||
*/
|
||||
a_util::result::Result setElementValue(size_t index, const a_util::variant::Variant& value);
|
||||
|
||||
/**
|
||||
* @param[in] index The index of the element.
|
||||
* @return A pointer to the element or NULL in case of an error.
|
||||
*/
|
||||
void* getElementAddress(size_t index);
|
||||
using StaticDecoder::getElementAddress;
|
||||
|
||||
/**
|
||||
* Sets all elements to their constant values defined in the DDL.
|
||||
* @return Standard result.
|
||||
*/
|
||||
a_util::result::Result setConstants();
|
||||
|
||||
private:
|
||||
friend class CodecFactory;
|
||||
/// For internal use only. @internal
|
||||
StaticCodec(a_util::memory::shared_ptr<const StructLayout> layout, void* data, size_t data_size,
|
||||
DataRepresentation rep);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
115
codec/struct_element.h
Normal file
115
codec/struct_element.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef DDL_STRUCT_ELEMENT_CLASS_HEADER
|
||||
#define DDL_STRUCT_ELEMENT_CLASS_HEADER
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "a_util/variant.h"
|
||||
#include "a_util/result.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
/**
|
||||
* Enumeration for the data representation
|
||||
*/
|
||||
enum DataRepresentation
|
||||
{
|
||||
serialized, ///< serialized data, i.e network, on disks, can msgs, ...
|
||||
deserialized ///< deserialized data, c-structs, arrays, ...
|
||||
};
|
||||
|
||||
/**
|
||||
* Typedef for enumerations name -> value.
|
||||
*/
|
||||
typedef std::map<std::string, a_util::variant::Variant> EnumType;
|
||||
|
||||
/**
|
||||
* Information about an element accessible with a decoder or codec.
|
||||
*/
|
||||
struct StructElement
|
||||
{
|
||||
std::string name; ///< The full name of the element.
|
||||
a_util::variant::VariantType type; ///< The type of the element.
|
||||
const EnumType* p_enum; ///< pointer to an enum, can be NULL.
|
||||
};
|
||||
|
||||
// The following classes are for internal use only
|
||||
|
||||
/**
|
||||
* \cond INTERNAL
|
||||
*/
|
||||
|
||||
struct Position
|
||||
{
|
||||
size_t bit_offset;
|
||||
size_t bit_size;
|
||||
};
|
||||
|
||||
struct StructLayoutElement: public StructElement
|
||||
{
|
||||
Position deserialized;
|
||||
Position serialized;
|
||||
int byte_order;
|
||||
const a_util::variant::Variant* constant;
|
||||
};
|
||||
|
||||
struct DynamicStructLayoutElement
|
||||
{
|
||||
std::string name;
|
||||
size_t alignment;
|
||||
std::string size_element_name;
|
||||
std::vector<StructLayoutElement> static_elements;
|
||||
std::vector<DynamicStructLayoutElement> dynamic_elements;
|
||||
|
||||
DynamicStructLayoutElement() = default;
|
||||
|
||||
DynamicStructLayoutElement(size_t alignment):
|
||||
alignment(alignment)
|
||||
{
|
||||
}
|
||||
|
||||
bool isAlignmentElement() const
|
||||
{
|
||||
return name.empty();
|
||||
}
|
||||
|
||||
bool isDynamicArray() const
|
||||
{
|
||||
return !size_element_name.empty();
|
||||
}
|
||||
};
|
||||
|
||||
struct Offsets
|
||||
{
|
||||
size_t deserialized;
|
||||
size_t serialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* \endcond INTERNAL
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
345
codec/struct_layout.cpp
Normal file
345
codec/struct_layout.cpp
Normal file
|
@ -0,0 +1,345 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#include "a_util/result/error_def.h"
|
||||
#include "legacy_error_macros.h"
|
||||
|
||||
#include "struct_layout.h"
|
||||
|
||||
#include <ddl.h>
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
//define all needed error types and values locally
|
||||
_MAKE_RESULT(-5, ERR_INVALID_ARG)
|
||||
_MAKE_RESULT(-19, ERR_NOT_SUPPORTED)
|
||||
_MAKE_RESULT(-37, ERR_NOT_INITIALIZED)
|
||||
|
||||
StructLayout::StructLayout(const DDLComplex* pStruct)
|
||||
{
|
||||
_static_buffer_sizes.deserialized = 0;
|
||||
_static_buffer_sizes.serialized = 0;
|
||||
_calculations_result = calculate(pStruct);
|
||||
}
|
||||
|
||||
StructLayout::StructLayout():
|
||||
_calculations_result(ERR_NOT_INITIALIZED)
|
||||
{
|
||||
_static_buffer_sizes.deserialized = 0;
|
||||
_static_buffer_sizes.serialized = 0;
|
||||
}
|
||||
|
||||
#define IF_TYPE(__type, __vtype, __size) \
|
||||
if (strType == __type) \
|
||||
{ \
|
||||
type = a_util::variant::__vtype;\
|
||||
nTypeSize = __size; \
|
||||
return a_util::result::SUCCESS; \
|
||||
}
|
||||
|
||||
static a_util::result::Result getType(const std::string& strType, a_util::variant::VariantType& type, size_t& nTypeSize)
|
||||
{
|
||||
IF_TYPE("tBool", VT_Bool, 8)
|
||||
else IF_TYPE("tChar", VT_Int8, 8)
|
||||
else IF_TYPE("tInt8", VT_Int8, 8)
|
||||
else IF_TYPE("tUInt8", VT_UInt8, 8)
|
||||
else IF_TYPE("tInt16", VT_Int16, 16)
|
||||
else IF_TYPE("tUInt16", VT_UInt16, 16)
|
||||
else IF_TYPE("tInt32", VT_Int32, 32)
|
||||
else IF_TYPE("tUInt32", VT_UInt32, 32)
|
||||
else IF_TYPE("tInt64", VT_Int64, 64)
|
||||
else IF_TYPE("tUInt64", VT_UInt64, 64)
|
||||
else IF_TYPE("tFloat32", VT_Float32, 32)
|
||||
else IF_TYPE("tFloat64", VT_Float64, 64)
|
||||
|
||||
return ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
class cConverter
|
||||
{
|
||||
public:
|
||||
cConverter(std::vector<StructLayoutElement>& static_elements,
|
||||
std::vector<DynamicStructLayoutElement>& dynamic_elements,
|
||||
std::map<std::string, EnumType>& oEnums):
|
||||
m_bDynamicSectionStarted(false),
|
||||
_static_elements(static_elements),
|
||||
_dynamic_elements(dynamic_elements),
|
||||
_enums(oEnums)
|
||||
{
|
||||
m_sOffsets.deserialized = 0;
|
||||
m_sOffsets.serialized = 0;
|
||||
}
|
||||
|
||||
a_util::result::Result Convert(DDLComplex* pStruct)
|
||||
{
|
||||
return addStruct(pStruct, "", m_sOffsets.serialized, pStruct->getDDLVersion() >= DDLVersion::ddl_version_30);
|
||||
}
|
||||
|
||||
Offsets getStaticBufferBitSizes()
|
||||
{
|
||||
return m_sOffsets;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// we are not using a standard visitor pattern because we would have to recreate a stack
|
||||
// for passing along all the additional parameters
|
||||
a_util::result::Result Add(IDDLDataType* pType, const std::string& strFullName, size_t& nSerializedOffset,
|
||||
int byte_order, int nNumBits, const std::string& strConstant, bool is_last_array_element)
|
||||
{
|
||||
DDLDataType* pPODType = dynamic_cast<DDLDataType*>(pType);
|
||||
DDLEnum* p_enum = dynamic_cast<DDLEnum*>(pType);
|
||||
EnumType* pCodecEnum = NULL;
|
||||
if (p_enum)
|
||||
{
|
||||
pPODType = dynamic_cast<DDLDataType*>(p_enum->getTypeObject());
|
||||
pCodecEnum = GetCodecEnum(p_enum);
|
||||
}
|
||||
|
||||
if (pPODType)
|
||||
{
|
||||
return AddPODElement(pPODType, strFullName, nSerializedOffset, byte_order,
|
||||
nNumBits, pCodecEnum, strConstant);
|
||||
}
|
||||
else
|
||||
{
|
||||
DDLComplex* pStruct = dynamic_cast<DDLComplex*>(pType);
|
||||
if (pStruct)
|
||||
{
|
||||
return addStruct(pStruct, strFullName, nSerializedOffset,
|
||||
// prior to DDL 3.0 the last array element is not padded to the alignment
|
||||
!is_last_array_element || pStruct->getDDLVersion() >= DDLVersion::ddl_version_30);
|
||||
}
|
||||
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
EnumType* GetCodecEnum(DDLEnum* p_enum)
|
||||
{
|
||||
std::map<std::string, EnumType>::iterator itEnum = _enums.find(p_enum->getName());
|
||||
if (itEnum == _enums.end())
|
||||
{
|
||||
EnumType oCodecEnum;
|
||||
const EnumNameValueVec& vecValues = p_enum->getValues();
|
||||
for (EnumNameValueVec::const_iterator it = vecValues.begin(); it != vecValues.end(); ++it)
|
||||
{
|
||||
oCodecEnum.insert(std::make_pair(it->first, a_util::variant::Variant(it->second.c_str())));
|
||||
}
|
||||
itEnum = _enums.insert(std::make_pair(p_enum->getName(), oCodecEnum)).first;
|
||||
}
|
||||
return &itEnum->second;
|
||||
}
|
||||
|
||||
a_util::result::Result AddPODElement(DDLDataType* pDataType, const std::string& strFullName,
|
||||
size_t& nSerializedOffset, int byte_order, int nNumBits,
|
||||
EnumType* p_enum,
|
||||
const std::string& strConstant)
|
||||
{
|
||||
StructLayoutElement sElement;
|
||||
sElement.name = strFullName;
|
||||
RETURN_IF_FAILED(getType(pDataType->getName(), sElement.type, sElement.deserialized.bit_size));
|
||||
sElement.deserialized.bit_offset = m_sOffsets.deserialized;
|
||||
sElement.serialized.bit_offset = nSerializedOffset;
|
||||
sElement.serialized.bit_size = nNumBits ? nNumBits : pDataType->getNumBits();
|
||||
sElement.byte_order = byte_order;
|
||||
sElement.p_enum = p_enum;
|
||||
sElement.constant = FindConstant(strConstant);
|
||||
_static_elements.push_back(sElement);
|
||||
|
||||
m_sOffsets.deserialized += sElement.deserialized.bit_size;
|
||||
nSerializedOffset += sElement.serialized.bit_size;
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
const a_util::variant::Variant* FindConstant(const std::string& strConstant)
|
||||
{
|
||||
if (!strConstant.empty())
|
||||
{
|
||||
for (std::map<std::string, EnumType>::const_iterator it = _enums.begin(); it != _enums.end(); ++it)
|
||||
{
|
||||
EnumType::const_iterator itValue = it->second.find(strConstant);
|
||||
if (itValue != it->second.end())
|
||||
{
|
||||
return &itValue->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
a_util::result::Result addStruct(DDLComplex* pStruct, const std::string& strFullName, size_t& nSerializedOffset, bool resize_to_alignment)
|
||||
{
|
||||
std::string strStructPrefix = (!strFullName.empty()) ? strFullName + "." : "";
|
||||
|
||||
bool bWasDynamicSectionStartedBefore = m_bDynamicSectionStarted;
|
||||
size_t nStructBaseOffset = m_sOffsets.deserialized;
|
||||
|
||||
size_t nMaxSerializedOffset = nSerializedOffset;
|
||||
DDLElementVec& vecElements = pStruct->getElements();
|
||||
for (DDLElementVec::iterator it = vecElements.begin(); it != vecElements.end(); ++it)
|
||||
{
|
||||
size_t nElementOffset = nSerializedOffset;
|
||||
RETURN_IF_FAILED(addElement(*it, strStructPrefix,
|
||||
nElementOffset,
|
||||
nStructBaseOffset));
|
||||
nMaxSerializedOffset = std::max(nMaxSerializedOffset, nElementOffset);
|
||||
}
|
||||
nSerializedOffset = nMaxSerializedOffset;
|
||||
|
||||
if (resize_to_alignment)
|
||||
{
|
||||
MoveOffsetToAlignment(pStruct->getAlignment(), nStructBaseOffset);
|
||||
}
|
||||
|
||||
if (m_bDynamicSectionStarted && !bWasDynamicSectionStartedBefore)
|
||||
{
|
||||
// add an alignment marker to ensure that the next element starts at the
|
||||
// correct position
|
||||
_dynamic_elements.push_back(pStruct->getAlignment());
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
void MoveOffsetToAlignment(DDLAlignment::AlignmentType eAlignment, size_t alignment_base_offset)
|
||||
{
|
||||
size_t nRelativeOffset = m_sOffsets.deserialized - alignment_base_offset;
|
||||
size_t nBitRest = nRelativeOffset % 8;
|
||||
if (nBitRest)
|
||||
{
|
||||
nRelativeOffset += 8 - nBitRest;
|
||||
}
|
||||
|
||||
size_t nByteOffset = nRelativeOffset / 8;
|
||||
size_t nRest = nByteOffset % eAlignment;
|
||||
if (nRest)
|
||||
{
|
||||
nRelativeOffset += (eAlignment - nRest) * 8;
|
||||
}
|
||||
m_sOffsets.deserialized = alignment_base_offset + nRelativeOffset;
|
||||
}
|
||||
|
||||
a_util::result::Result addElement(DDLElement* pElement, const std::string& strStructPrefix, size_t& nSerializedOffset, size_t nStructBaseOffset)
|
||||
{
|
||||
if (!m_bDynamicSectionStarted)
|
||||
{
|
||||
m_bDynamicSectionStarted = pElement->getArraysize() == 0;
|
||||
}
|
||||
|
||||
if (!m_bDynamicSectionStarted)
|
||||
{
|
||||
MoveOffsetToAlignment(pElement->getAlignment(), nStructBaseOffset);
|
||||
nSerializedOffset += pElement->getBytepos() * 8 + pElement->getBitpos();
|
||||
}
|
||||
|
||||
size_t nArraySize = std::max(pElement->getArraysize(), 1u);
|
||||
for (size_t nArrayIndex = 0; nArrayIndex < nArraySize; ++nArrayIndex)
|
||||
{
|
||||
std::string strCurrentElementName = strStructPrefix + pElement->getName();
|
||||
if (nArraySize > 1)
|
||||
{
|
||||
strCurrentElementName += a_util::strings::format("[%d]", nArrayIndex);
|
||||
}
|
||||
|
||||
if (!m_bDynamicSectionStarted)
|
||||
{
|
||||
RETURN_IF_FAILED(Add(pElement->getTypeObject(), strCurrentElementName,
|
||||
nSerializedOffset, pElement->getByteorder(),
|
||||
pElement->getNumBits(),
|
||||
pElement->getConstantValue(),
|
||||
nArrayIndex == nArraySize - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_IF_FAILED(addDynamicElement(pElement, strCurrentElementName, strStructPrefix));
|
||||
}
|
||||
}
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
a_util::result::Result addDynamicElement(const DDLElement* pElement, const std::string& strFullName,
|
||||
const std::string& strStructPrefix)
|
||||
{
|
||||
DynamicStructLayoutElement sDynamicElement;
|
||||
|
||||
cConverter oChildConverter(sDynamicElement.static_elements,
|
||||
sDynamicElement.dynamic_elements,
|
||||
_enums);
|
||||
size_t nDummy = 0;
|
||||
RETURN_IF_FAILED(oChildConverter.Add(pElement->getTypeObject(), "",
|
||||
nDummy, pElement->getByteorder(),
|
||||
pElement->getNumBits(),
|
||||
pElement->getConstantValue(),
|
||||
false));
|
||||
|
||||
sDynamicElement.name = strFullName;
|
||||
sDynamicElement.alignment = pElement->getAlignment();
|
||||
|
||||
if (pElement->getArraysize() == 0)
|
||||
{
|
||||
if (pElement->getArraySizeSource().empty())
|
||||
{
|
||||
return ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
sDynamicElement.size_element_name = strStructPrefix + pElement->getArraySizeSource();
|
||||
}
|
||||
|
||||
_dynamic_elements.push_back(sDynamicElement);
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
Offsets m_sOffsets;
|
||||
bool m_bDynamicSectionStarted;
|
||||
std::vector<StructLayoutElement>& _static_elements;
|
||||
std::vector<DynamicStructLayoutElement>& _dynamic_elements;
|
||||
std::map<std::string, EnumType>& _enums;
|
||||
};
|
||||
|
||||
a_util::result::Result StructLayout::calculate(const DDLComplex* pStruct)
|
||||
{
|
||||
cConverter oConverter(_static_elements,
|
||||
_dynamic_elements,
|
||||
_enums);
|
||||
RETURN_IF_FAILED(oConverter.Convert(const_cast<DDLComplex*>(pStruct)));
|
||||
_static_buffer_sizes = oConverter.getStaticBufferBitSizes();
|
||||
|
||||
return a_util::result::SUCCESS;
|
||||
}
|
||||
|
||||
size_t StructLayout::getStaticBufferSize(DataRepresentation eRep) const
|
||||
{
|
||||
size_t nResult = eRep == deserialized ?
|
||||
_static_buffer_sizes.deserialized :
|
||||
_static_buffer_sizes.serialized;
|
||||
if (nResult % 8)
|
||||
{
|
||||
return nResult / 8 + 1;
|
||||
}
|
||||
return nResult / 8;
|
||||
}
|
||||
|
||||
}
|
||||
|
87
codec/struct_layout.h
Normal file
87
codec/struct_layout.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* @file
|
||||
* Implementation of the ADTF default media description.
|
||||
*
|
||||
* @copyright
|
||||
* @verbatim
|
||||
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla
|
||||
Public License, v. 2.0. If a copy of the MPL was not distributed
|
||||
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, then
|
||||
You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
#ifndef DDL_STRUCT_LAYOUT_CLASS_HEADER
|
||||
#define DDL_STRUCT_LAYOUT_CLASS_HEADER
|
||||
|
||||
#include "struct_element.h"
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
|
||||
class DDLComplex;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* This class is for internal use only.
|
||||
*/
|
||||
class StructLayout
|
||||
{
|
||||
public:
|
||||
StructLayout();
|
||||
StructLayout(const DDLComplex* ddl_struct);
|
||||
|
||||
a_util::result::Result isValid() const
|
||||
{
|
||||
return _calculations_result;
|
||||
}
|
||||
|
||||
const std::vector<StructLayoutElement>& getStaticElements() const
|
||||
{
|
||||
return _static_elements;
|
||||
}
|
||||
|
||||
const std::vector<DynamicStructLayoutElement>& getDynamicElements() const
|
||||
{
|
||||
return _dynamic_elements;
|
||||
}
|
||||
|
||||
bool hasDynamicElements() const
|
||||
{
|
||||
return !_dynamic_elements.empty();
|
||||
}
|
||||
|
||||
bool hasEnums() const
|
||||
{
|
||||
return !_enums.empty();
|
||||
}
|
||||
|
||||
const Offsets& getStaticBufferBitSizes() const
|
||||
{
|
||||
return _static_buffer_sizes;
|
||||
}
|
||||
|
||||
size_t getStaticBufferSize(DataRepresentation rep) const;
|
||||
|
||||
private:
|
||||
a_util::result::Result calculate(const DDLComplex* ddl_struct);
|
||||
|
||||
private:
|
||||
std::vector<StructLayoutElement> _static_elements;
|
||||
std::vector<DynamicStructLayoutElement> _dynamic_elements;
|
||||
std::map<std::string, EnumType> _enums;
|
||||
Offsets _static_buffer_sizes;
|
||||
a_util::result::Result _calculations_result;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue