diff --git a/src/cpp/xmlparser/XMLDynamicParser.cpp b/src/cpp/xmlparser/XMLDynamicParser.cpp new file mode 100644 index 00000000000..b12ec644821 --- /dev/null +++ b/src/cpp/xmlparser/XMLDynamicParser.cpp @@ -0,0 +1,1964 @@ +// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "../fastdds/xtypes/dynamic_types/AnnotationDescriptorImpl.hpp" +#include "../fastdds/xtypes/dynamic_types/DynamicTypeImpl.hpp" +#include "../fastdds/xtypes/dynamic_types/MemberDescriptorImpl.hpp" +#include "../fastdds/xtypes/dynamic_types/TypeDescriptorImpl.hpp" + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastdds; +using namespace eprosima::fastdds::rtps; +using namespace eprosima::fastdds::xmlparser; + +//{{{ Auxiliary constexpr function to get the length of a const char* in C++11. +constexpr size_t constexpr_strlen_rec( + const char* const str, + size_t length) +{ + return '\0' == str[length] ? length : constexpr_strlen_rec(str, length + 1); +} + +constexpr size_t constexpr_strlen( + const char* const str) +{ + return constexpr_strlen_rec(str, 0) + 1; +} + +//}}} + +// TYPES parser +constexpr const char* const BOOLEAN = "boolean"; +constexpr size_t BOOLEAN_len = constexpr_strlen(BOOLEAN); +constexpr const char* const CHAR = "char8"; +constexpr size_t CHAR_len = constexpr_strlen(CHAR); +constexpr const char* const WCHAR = "char16"; +constexpr size_t WCHAR_len = constexpr_strlen(WCHAR); +constexpr const char* const TBYTE = "byte"; +constexpr size_t TBYTE_len = constexpr_strlen(TBYTE); +constexpr const char* const OCTET = "octet"; +constexpr size_t OCTET_len = constexpr_strlen(OCTET); +constexpr const char* const UINT8 = "uint8"; +constexpr size_t UINT8_len = constexpr_strlen(UINT8); +constexpr const char* const INT8 = "int8"; +constexpr size_t INT8_len = constexpr_strlen(INT8); +constexpr const char* const SHORT = "int16"; +constexpr size_t SHORT_len = constexpr_strlen(SHORT); +constexpr const char* const LONG = "int32"; +constexpr size_t LONG_len = constexpr_strlen(LONG); +constexpr const char* const USHORT = "uint16"; +constexpr size_t USHORT_len = constexpr_strlen(USHORT); +constexpr const char* const ULONG = "uint32"; +constexpr size_t ULONG_len = constexpr_strlen(ULONG); +constexpr const char* const LONGLONG = "int64"; +constexpr size_t LONGLONG_len = constexpr_strlen(LONGLONG); +constexpr const char* const ULONGLONG = "uint64"; +constexpr size_t ULONGLONG_len = constexpr_strlen(ULONGLONG); +constexpr const char* const FLOAT = "float32"; +constexpr size_t FLOAT_len = constexpr_strlen(FLOAT); +constexpr const char* const DOUBLE = "float64"; +constexpr size_t DOUBLE_len = constexpr_strlen(DOUBLE); +constexpr const char* const LONGDOUBLE = "float128"; +constexpr size_t LONGDOUBLE_len = constexpr_strlen(LONGDOUBLE); +constexpr const char* const STRING = "string"; +constexpr size_t STRING_len = constexpr_strlen(STRING); +constexpr const char* const WSTRING = "wstring"; +constexpr size_t WSTRING_len = constexpr_strlen(WSTRING); +constexpr const char* const STRUCT = "struct"; +constexpr const char* const UNION = "union"; +constexpr const char* const TYPEDEF = "typedef"; +constexpr const char* const BITSET = "bitset"; +constexpr const char* const BITMASK = "bitmask"; +constexpr const char* const ENUM = "enum"; +constexpr const char* const CASE = "case"; +constexpr const char* const DEFAULT = "default"; +constexpr const char* const DISCRIMINATOR = "discriminator"; +constexpr const char* const CASE_DISCRIMINATOR = "caseDiscriminator"; +constexpr size_t CASE_DISCRIMINATOR_len = constexpr_strlen(CASE_DISCRIMINATOR); +constexpr const char* const ARRAY_DIMENSIONS = "arrayDimensions"; +constexpr const char* const STR_MAXLENGTH = "stringMaxLength"; +constexpr const char* const SEQ_MAXLENGTH = "sequenceMaxLength"; +constexpr const char* const MAP_MAXLENGTH = "mapMaxLength"; +constexpr const char* const MAP_KEY_TYPE = "key_type"; +constexpr const char* const ENUMERATOR = "enumerator"; +constexpr const char* const NON_BASIC_TYPE = "nonBasic"; +constexpr const char* const NON_BASIC_TYPE_NAME = "nonBasicTypeName"; +constexpr const char* const KEY = "key"; +constexpr const char* const MEMBER = "member"; +constexpr const char* const BITFIELD = "bitfield"; +constexpr const char* const BIT_VALUE = "bit_value"; +constexpr const char* const POSITION = "position"; +constexpr const char* const BIT_BOUND = "bit_bound"; +constexpr const char* const BASE_TYPE = "baseType"; + +XMLP_ret XMLParser::parseXMLDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + + */ + XMLP_ret ret = XMLP_ret::XML_OK; + tinyxml2::XMLElement* p_aux0 = nullptr; + for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) + { + const std::string type = p_aux0->Value(); + if (type.compare(STRUCT) == 0) + { + ret = parseXMLStructDynamicType(p_aux0); + } + else if (type.compare(UNION) == 0) + { + ret = parseXMLUnionDynamicType(p_aux0); + } + else if (type.compare(ENUM) == 0) + { + ret = parseXMLEnumDynamicType(p_aux0); + } + else if (type.compare(TYPEDEF) == 0) + { + ret = parseXMLAliasDynamicType(p_aux0); + } + else if (type.compare(BITSET) == 0) + { + ret = parseXMLBitsetDynamicType(p_aux0); + } + else if (type.compare(BITMASK) == 0) + { + ret = parseXMLBitmaskDynamicType(p_aux0); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing type: Type " << type << " not recognized."); + ret = XMLP_ret::XML_ERROR; + } + + if (ret != XMLP_ret::XML_OK) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing type " << type << "."); + break; + } + } + return ret; +} + +XMLP_ret XMLParser::parseXMLTypes( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + */ + + XMLP_ret ret = XMLP_ret::XML_OK; + tinyxml2::XMLElement* p_aux0 = nullptr, * p_aux1 = nullptr; + p_aux0 = p_root->FirstChildElement(TYPES); + if (p_aux0 != nullptr) + { + const char* name = nullptr; + for (p_aux1 = p_aux0->FirstChildElement(); p_aux1 != nullptr; p_aux1 = p_aux1->NextSiblingElement()) + { + name = p_aux1->Name(); + if (strcmp(name, TYPE) == 0) + { + if (XMLP_ret::XML_OK != parseXMLDynamicType(p_aux1)) + { + return XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid element found into 'types'. Name: " << name); + return XMLP_ret::XML_ERROR; + } + } + } + else // Directly root is TYPES? + { + const char* name = nullptr; + for (p_aux0 = p_root->FirstChildElement(); p_aux0 != nullptr; p_aux0 = p_aux0->NextSiblingElement()) + { + name = p_aux0->Name(); + if (strcmp(name, TYPE) == 0) + { + if (XMLP_ret::XML_OK != parseXMLDynamicType(p_aux0)) + { + return XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid element found into 'types'. Name: " << name); + return XMLP_ret::XML_ERROR; + } + } + } + return ret; +} + +XMLP_ret XMLParser::parseXMLBitvalueDynamicType( + tinyxml2::XMLElement* p_root, + DynamicTypeBuilder::_ref_type builder, + uint16_t& field_position) +{ + /* + + + + + */ + if (p_root == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bitmask: Node not found."); + return XMLP_ret::XML_ERROR; + } + + if (!builder) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bitmask: builder is nil."); + return XMLP_ret::XML_ERROR; + } + + const char* memberName = p_root->Attribute(NAME); + const char* position = p_root->Attribute(POSITION); + + if (position != nullptr) + { + try + { + field_position = static_cast(std::stoul(position)); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bit_value position: Invalid (must be an unsigned short)."); + return XMLP_ret::XML_ERROR; + } + } + + if (memberName == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bit_value name: Not found."); + return XMLP_ret::XML_ERROR; + } + + MemberDescriptor::_ref_type md {traits::make_shared()}; + md->id(field_position); + md->name(memberName); + md->type(DynamicTypeBuilderFactory::get_instance()->get_primitive_type(TK_BOOLEAN)); + builder->add_member(md); + ++field_position; + + return XMLP_ret::XML_OK; +} + +static DynamicType::_ref_type getDiscriminatorTypeBuilder( + const std::string& disc, + uint32_t bound = 0) +{ + /* + mKind == TK_BOOLEAN || mKind == TK_BYTE || mKind == TK_INT16 || mKind == TK_INT32 || + mKind == TK_INT64 || mKind == TK_UINT16 || mKind == TK_UINT32 || mKind == TK_UINT64 || + mKind == TK_FLOAT32 || mKind == TK_FLOAT64 || mKind == TK_FLOAT128 || mKind == TK_CHAR8 || + mKind == TK_CHAR16 || mKind == TK_STRING8 || mKind == TK_STRING16 || mKind == TK_ENUM || mKind == TK_BITMASK + */ + auto factory = DynamicTypeBuilderFactory::get_instance(); + if (0 == disc.compare(BOOLEAN)) + { + return factory->get_primitive_type(TK_BOOLEAN); + } + else if (0 == disc.compare(TBYTE) || + 0 == disc.compare(OCTET)) + { + return factory->get_primitive_type(TK_BYTE); + } + else if (0 == disc.compare(INT8)) + { + return factory->get_primitive_type(TK_INT8); + } + else if (0 == disc.compare(UINT8)) + { + return factory->get_primitive_type(TK_UINT8); + } + else if (0 == disc.compare(SHORT)) + { + return factory->get_primitive_type(TK_INT16); + } + else if (0 == disc.compare(LONG)) + { + return factory->get_primitive_type(TK_INT32); + } + else if (0 == disc.compare(LONGLONG)) + { + return factory->get_primitive_type(TK_INT64); + } + else if (0 == disc.compare(USHORT)) + { + return factory->get_primitive_type(TK_UINT16); + } + else if (0 == disc.compare(ULONG)) + { + return factory->get_primitive_type(TK_UINT32); + } + else if (0 == disc.compare(ULONGLONG)) + { + return factory->get_primitive_type(TK_UINT64); + } + else if (0 == disc.compare(FLOAT)) + { + return factory->get_primitive_type(TK_FLOAT32); + } + else if (0 == disc.compare(DOUBLE)) + { + return factory->get_primitive_type(TK_FLOAT64); + } + else if (0 == disc.compare(LONGDOUBLE)) + { + return factory->get_primitive_type(TK_FLOAT128); + } + else if (0 == disc.compare(CHAR)) + { + return factory->get_primitive_type(TK_CHAR8); + } + else if (0 == disc.compare(WCHAR)) + { + return factory->get_primitive_type(TK_CHAR16); + } + else if (0 == disc.compare(STRING)) + { + return factory->create_string_type(0 == bound ? static_cast(LENGTH_UNLIMITED) : bound)->build(); + } + else if (0 == disc.compare(WSTRING)) + { + return factory->create_wstring_type(0 == bound ? static_cast(LENGTH_UNLIMITED) : bound)->build(); + } + + DynamicTypeBuilder::_ref_type ret; + XMLProfileManager::getDynamicTypeBuilderByName(ret, disc); + if (nullptr != ret) + { + return ret->build(); + } + else + { + return nullptr; + } + +} + +XMLP_ret XMLParser::parseXMLAliasDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + + + */ + XMLP_ret ret = XMLP_ret::XML_OK; + + const char* type = p_root->Attribute(TYPE); + if (type != nullptr) + { + if (strcmp(type, NON_BASIC_TYPE) == 0) + { + const char* typeNonBasicName = p_root->Attribute(NON_BASIC_TYPE_NAME); + if (typeNonBasicName != nullptr) + { + type = typeNonBasicName; + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing member type: Not found."); + ret = XMLP_ret::XML_ERROR; + } + } + + DynamicType::_ref_type value_type; + if ((p_root->Attribute(ARRAY_DIMENSIONS) != nullptr) || + (p_root->Attribute(SEQ_MAXLENGTH) != nullptr) || + (p_root->Attribute(MAP_MAXLENGTH) != nullptr)) + { + value_type = parseXMLMemberDynamicType(p_root); + } + else + { + uint32_t bound = 0; + const char* boundStr = p_root->Attribute(STR_MAXLENGTH); + if (boundStr != nullptr) + { + try + { + bound = static_cast(std::stoul(boundStr)); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing alias type bound: '" << STR_MAXLENGTH << "' out of bounds."); + return XMLP_ret::XML_ERROR; + } + } + value_type = getDiscriminatorTypeBuilder(type, bound); + } + + if (value_type) + { + const char* name = p_root->Attribute(NAME); + if (name != nullptr && name[0] != '\0') + { + DynamicTypeBuilder::_ref_type aux_type; + XMLProfileManager::getDynamicTypeBuilderByName(aux_type, name); + if (!aux_type) + { + TypeDescriptor::_ref_type alias_descriptor {traits::make_shared()}; + alias_descriptor->kind(TK_ALIAS); + alias_descriptor->name(name); + alias_descriptor->base_type(value_type); + DynamicTypeBuilder::_ref_type builder {DynamicTypeBuilderFactory::get_instance()->create_type( + alias_descriptor)}; + if (nullptr == builder + || false == XMLProfileManager::insertDynamicTypeBuilderByName(name, builder)) + { + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing alias type: Type '" << name << "' already defined."); + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing alias type: No name attribute given."); + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing alias type: Value not recognized."); + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing alias type: Type not defined."); + ret = XMLP_ret::XML_ERROR; + } + return ret; +} + +XMLP_ret XMLParser::parseXMLBitsetDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + + + + + + + */ + XMLP_ret ret = XMLP_ret::XML_OK; + + const char* name = p_root->Attribute(NAME); + if (nullptr == name || name[0] == '\0') + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'bitsetDcl' type. No name attribute given."); + return XMLP_ret::XML_ERROR; + } + + DynamicTypeBuilder::_ref_type aux_type; + XMLProfileManager::getDynamicTypeBuilderByName(aux_type, name); + if (aux_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'bitsetDcl' type: Type '" << name << "' already defined."); + return XMLP_ret::XML_ERROR; + } + + TypeDescriptor::_ref_type bitset_descriptor {traits::make_shared()}; + bitset_descriptor->kind(TK_BITSET); + bitset_descriptor->name(name); + + //{{{ Retrieve bounds + for (tinyxml2::XMLElement* p_element = p_root->FirstChildElement(); + p_element != nullptr; p_element = p_element->NextSiblingElement()) + { + const char* member_name = p_element->Attribute(NAME); + const char* bit_bound = p_element->Attribute(BIT_BOUND); + + if (bit_bound == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bitfield bit_bound: Not found."); + return XMLP_ret::XML_ERROR; + } + if (nullptr != member_name) + { + try + { + bitset_descriptor->bound().push_back(static_cast(std::stoul(bit_bound))); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing bitfield type bound: '" << BIT_BOUND << "' out of bounds."); + return XMLP_ret::XML_ERROR; + } + } + } + //}}} + + const char* baseType = p_root->Attribute(BASE_TYPE); + if (baseType != nullptr) + { + DynamicTypeBuilder::_ref_type parent_type_builder = nullptr; + XMLProfileManager::getDynamicTypeBuilderByName(parent_type_builder, baseType); + + DynamicType::_ref_type parent_type = nullptr; + + if (nullptr != parent_type_builder) + { + parent_type = parent_type_builder->build(); + } + + if (parent_type && (TK_BITSET == parent_type->get_kind() || + TK_BITSET == + traits::narrow(parent_type)->resolve_alias_enclosed_type()->get_kind())) + { + bitset_descriptor->base_type(parent_type); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid baseType found into 'bitsetDcl'. Name: " << baseType); + return XMLP_ret::XML_ERROR; + } + } + + DynamicTypeBuilder::_ref_type type_builder = + DynamicTypeBuilderFactory::get_instance()->create_type(bitset_descriptor); + + if (nullptr != type_builder) + { + const char* element_name {nullptr}; + MemberId position {0}; + for (tinyxml2::XMLElement* p_element = p_root->FirstChildElement(); + p_element != nullptr; p_element = p_element->NextSiblingElement()) + { + element_name = p_element->Name(); + if (strcmp(element_name, BITFIELD) == 0) + { + ret = parseXMLBitfieldDynamicType(p_element, type_builder, position); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid element found into 'bitsetDcl'. Name: " << element_name); + return XMLP_ret::XML_ERROR; + } + } + + if (XMLP_ret::XML_OK == ret) + { + if (false == XMLProfileManager::insertDynamicTypeBuilderByName(name, type_builder)) + { + ret = XMLP_ret::XML_ERROR; + } + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error creating bitset type: " << name); + ret = XMLP_ret::XML_ERROR; + } + + return ret; +} + +XMLP_ret XMLParser::parseXMLBitfieldDynamicType( + tinyxml2::XMLElement* p_root, + DynamicTypeBuilder::_ref_type builder, + MemberId& position) +{ + /* + + + + + + */ + if (p_root == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bitfield: Node not found."); + return XMLP_ret::XML_ERROR; + } + + if (!builder) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bitfield: builder is nil."); + return XMLP_ret::XML_ERROR; + } + + const char* memberType = p_root->Attribute(TYPE); + const char* memberName = p_root->Attribute(NAME); + const char* bit_bound = p_root->Attribute(BIT_BOUND); + + if (bit_bound == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing bitfield bit_bound: Not found."); + return XMLP_ret::XML_ERROR; + } + + DynamicType::_ref_type member_type; + DynamicTypeBuilderFactory::_ref_type factory = DynamicTypeBuilderFactory::get_instance(); + uint32_t size {0}; + + try + { + size = static_cast(std::stoul(bit_bound)); + } + catch (...) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Failed creating bitfield, invalid bit_bound (must be an unsigned short): " + << bit_bound); + return XMLP_ret::XML_ERROR; + } + + if (memberType == nullptr) + { + if (1 == size) + { + memberType = BOOLEAN; + } + else if (9 > size) + { + memberType = UINT8; + } + else if (17 > size) + { + memberType = USHORT; + } + else if (33 > size) + { + memberType = ULONG; + } + else if (65 > size) + { + memberType = ULONGLONG; + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Failed creating bitfield, size too big: " << bit_bound); + return XMLP_ret::XML_ERROR; + } + } + + if (nullptr != memberName) + { + + if (0 == strncmp(memberType, BOOLEAN, BOOLEAN_len)) + { + member_type = factory->get_primitive_type(TK_BOOLEAN); + } + else if (0 == strncmp(memberType, TBYTE, TBYTE_len) + || 0 == strncmp(memberType, OCTET, 6)) + { + member_type = factory->get_primitive_type(TK_BYTE); + } + else if (0 == strncmp(memberType, INT8, INT8_len)) + { + member_type = factory->get_primitive_type(TK_INT8); + } + else if (0 == strncmp(memberType, UINT8, UINT8_len)) + { + member_type = factory->get_primitive_type(TK_UINT8); + } + else if (0 == strncmp(memberType, SHORT, SHORT_len)) + { + member_type = factory->get_primitive_type(TK_INT16); + } + else if (0 == strncmp(memberType, LONG, LONG_len)) + { + member_type = factory->get_primitive_type(TK_INT32); + } + else if (0 == strncmp(memberType, ULONG, ULONG_len)) + { + member_type = factory->get_primitive_type(TK_UINT32); + } + else if (0 == strncmp(memberType, USHORT, USHORT_len)) + { + member_type = factory->get_primitive_type(TK_UINT16); + } + else if (0 == strncmp(memberType, LONGLONG, LONGLONG_len)) + { + member_type = factory->get_primitive_type(TK_INT64); + } + else if (0 == strncmp(memberType, ULONGLONG, ULONGLONG_len)) + { + member_type = factory->get_primitive_type(TK_UINT64); + } + else // Unsupported type + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Failed creating bitfield " << memberName << ": Type " << memberType << " unsupported."); + return XMLP_ret::XML_ERROR; + } + + MemberDescriptor::_ref_type md {traits::make_shared()}; + md->id(position); + md->name(memberName); + md->type(member_type); + builder->add_member(md); + } + + position += size; + + return XMLP_ret::XML_OK; +} + +XMLP_ret XMLParser::parseXMLBitmaskDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + + + + */ + XMLP_ret ret = XMLP_ret::XML_OK; + uint16_t bit_bound = 32; + const char* anno_bit_bound = p_root->Attribute(BIT_BOUND); + if (anno_bit_bound != nullptr) + { + auto input_bit_bound = std::atoi(anno_bit_bound); + if (input_bit_bound < 1 || input_bit_bound > 64) + { + return XMLP_ret::XML_ERROR; + } + bit_bound = static_cast(input_bit_bound); + } + + const char* name = p_root->Attribute(NAME); + if (nullptr == name || name[0] == '\0') + { + return XMLP_ret::XML_ERROR; + } + DynamicTypeBuilder::_ref_type aux_type; + XMLProfileManager::getDynamicTypeBuilderByName(aux_type, name); + if (aux_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'bitmaskDcl' type: Type '" << name << "' already defined."); + return XMLP_ret::XML_ERROR; + } + + TypeDescriptor::_ref_type bitmask_descriptor {traits::make_shared()}; + bitmask_descriptor->kind(TK_BITMASK); + bitmask_descriptor->name(name); + bitmask_descriptor->element_type(DynamicTypeBuilderFactory::get_instance()->get_primitive_type(TK_BOOLEAN)); + bitmask_descriptor->bound().push_back(bit_bound); + DynamicTypeBuilder::_ref_type type_builder { + DynamicTypeBuilderFactory::get_instance()->create_type(bitmask_descriptor)}; + uint16_t position = 0; + + if (nullptr != type_builder) + { + const char* element_name = nullptr; + for (tinyxml2::XMLElement* p_element = p_root->FirstChildElement(); + p_element != nullptr; p_element = p_element->NextSiblingElement()) + { + element_name = p_element->Name(); + if (strcmp(element_name, BIT_VALUE) == 0) + { + if (parseXMLBitvalueDynamicType(p_element, type_builder, position) != XMLP_ret::XML_OK) + { + return XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid element found into 'bitmaskDcl'. Name: " << element_name); + return XMLP_ret::XML_ERROR; + } + } + + if (false == XMLProfileManager::insertDynamicTypeBuilderByName(name, type_builder)) + { + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error creating bitmask type: " << name); + ret = XMLP_ret::XML_ERROR; + } + + return ret; +} + +XMLP_ret XMLParser::parseXMLEnumDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + + //TODO: Enum bitbound to set the internal field + */ + XMLP_ret ret = XMLP_ret::XML_OK; + const char* enumName = p_root->Attribute(NAME); + + if (enumName == nullptr || enumName[0] == '\0') + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'enum' type. No name attribute given."); + return XMLP_ret::XML_ERROR; + } + + DynamicTypeBuilder::_ref_type aux_type; + XMLProfileManager::getDynamicTypeBuilderByName(aux_type, enumName); + if (aux_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'enum' type: Type '" << enumName << "' already defined."); + return XMLP_ret::XML_ERROR; + } + + + TypeDescriptor::_ref_type enum_descriptor {traits::make_shared()}; + enum_descriptor->kind(TK_ENUM); + enum_descriptor->name(enumName); + DynamicTypeBuilder::_ref_type type_builder {DynamicTypeBuilderFactory::get_instance()->create_type( + enum_descriptor)}; + + if (nullptr != type_builder) + { + for (tinyxml2::XMLElement* literal = p_root->FirstChildElement(ENUMERATOR); + literal != nullptr; literal = literal->NextSiblingElement(ENUMERATOR)) + { + const char* name = literal->Attribute(NAME); + if (name == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing enum type: Literals must have name."); + return XMLP_ret::XML_ERROR; + } + + MemberDescriptor::_ref_type md {traits::make_shared()}; + md->type(DynamicTypeBuilderFactory::get_instance()->get_primitive_type(TK_INT32)); + md->name(name); + + const char* value = literal->Attribute(VALUE); + if (value != nullptr) + { + md->default_value(value); + } + + type_builder->add_member(md); + } + + if (false == XMLProfileManager::insertDynamicTypeBuilderByName(enumName, type_builder)) + { + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error creating enum type: " << enumName); + ret = XMLP_ret::XML_ERROR; + } + + return ret; +} + +XMLP_ret XMLParser::parseXMLStructDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + */ + XMLP_ret ret = XMLP_ret::XML_OK; + MemberId mId{0}; + const char* name = p_root->Attribute(NAME); + + if (nullptr == name || name[0] == '\0') + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Missing required attribute 'name' in 'structDcl'."); + return XMLP_ret::XML_ERROR; + } + + DynamicTypeBuilder::_ref_type aux_type; + XMLProfileManager::getDynamicTypeBuilderByName(aux_type, name); + if (aux_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'structDcl' type: Type '" << name << "' already defined."); + return XMLP_ret::XML_ERROR; + } + + TypeDescriptor::_ref_type structure_descriptor {traits::make_shared()}; + structure_descriptor->kind(TK_STRUCTURE); + structure_descriptor->name(name); + + const char* baseType = p_root->Attribute(BASE_TYPE); + if (baseType != nullptr) + { + DynamicTypeBuilder::_ref_type parent_type_builder = nullptr; + XMLProfileManager::getDynamicTypeBuilderByName(parent_type_builder, baseType); + + DynamicType::_ref_type parent_type = nullptr; + + if (nullptr != parent_type_builder) + { + parent_type = parent_type_builder->build(); + } + + if (parent_type && (TK_STRUCTURE == parent_type->get_kind() || + TK_STRUCTURE == + traits::narrow(parent_type)->resolve_alias_enclosed_type()->get_kind())) + { + structure_descriptor->base_type(parent_type); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid baseType found into 'structDcl'. Name: " << baseType); + return XMLP_ret::XML_ERROR; + } + } + + DynamicTypeBuilder::_ref_type type_builder = DynamicTypeBuilderFactory::get_instance()->create_type( + structure_descriptor); + + if (nullptr != type_builder) + { + const char* element_name = nullptr; + for (tinyxml2::XMLElement* p_element = p_root->FirstChildElement(); + p_element != nullptr; p_element = p_element->NextSiblingElement()) + { + element_name = p_element->Name(); + if (strcmp(element_name, MEMBER) == 0) + { + if (!parseXMLMemberDynamicType(p_element, type_builder, mId++)) + { + return XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Invalid element found into 'structDcl'. Name: " << element_name); + return XMLP_ret::XML_ERROR; + } + } + + if (false == XMLProfileManager::insertDynamicTypeBuilderByName(name, type_builder)) + { + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error creating struct type: " << name); + ret = XMLP_ret::XML_ERROR; + } + + return ret; +} + +XMLP_ret XMLParser::parseXMLUnionDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + + + + + + + + */ + + XMLP_ret ret = XMLP_ret::XML_OK; + const char* name = p_root->Attribute(NAME); + if (nullptr == name || name[0] == '\0') + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Missing required attribute 'name' in 'unionDcl'."); + return XMLP_ret::XML_ERROR; + } + + DynamicTypeBuilder::_ref_type aux_type; + XMLProfileManager::getDynamicTypeBuilderByName(aux_type, name); + if (aux_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing 'unionDcl' type: Type '" << name << "' already defined."); + return XMLP_ret::XML_ERROR; + } + + tinyxml2::XMLElement* p_element = p_root->FirstChildElement(DISCRIMINATOR); + if (p_element != nullptr) + { + const char* disc = p_element->Attribute(TYPE); + DynamicType::_ref_type disc_type = getDiscriminatorTypeBuilder(disc); + if (!disc_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing union discriminator: Only primitive types allowed (found type " << disc << ")."); + ret = XMLP_ret::XML_ERROR; + } + else + { + TypeDescriptor::_ref_type union_descriptor {traits::make_shared()}; + union_descriptor->kind(TK_UNION); + union_descriptor->name(name); + union_descriptor->discriminator_type(disc_type); + DynamicTypeBuilder::_ref_type type_builder {DynamicTypeBuilderFactory::get_instance()-> + create_type(union_descriptor)}; + + if (nullptr != type_builder) + { + MemberId mId{1}; + for (p_element = p_root->FirstChildElement(CASE); + p_element != nullptr; p_element = p_element->NextSiblingElement(CASE)) + { + std::string valuesStr = ""; + for (tinyxml2::XMLElement* caseValue = p_element->FirstChildElement(CASE_DISCRIMINATOR); + caseValue != nullptr; caseValue = caseValue->NextSiblingElement(CASE_DISCRIMINATOR)) + { + const char* values = caseValue->Attribute(VALUE); + if (values == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing union case value: Not found."); + return XMLP_ret::XML_ERROR; + } + + if (valuesStr.empty()) + { + valuesStr = values; + } + else + { + valuesStr += std::string(",") + values; + } + } + + tinyxml2::XMLElement* caseElement = p_element->FirstChildElement(); + while (caseElement != nullptr && + strncmp(caseElement->Value(), CASE_DISCRIMINATOR, CASE_DISCRIMINATOR_len) == 0) + { + caseElement = caseElement->NextSiblingElement(); + } + if (caseElement != nullptr) + { + if (!parseXMLMemberDynamicType(caseElement, type_builder, mId++, valuesStr)) + { + return XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing union case member: Not found."); + return XMLP_ret::XML_ERROR; + } + } + + if (false == XMLProfileManager::insertDynamicTypeBuilderByName(name, type_builder)) + { + ret = XMLP_ret::XML_ERROR; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error creating union type: " << name); + ret = XMLP_ret::XML_ERROR; + } + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing union discriminator: Not found."); + ret = XMLP_ret::XML_ERROR; + } + + return ret; +} + +static void dimensionsToArrayBounds( + const std::string& dimensions, + std::vector& bounds) +{ + std::stringstream ss(dimensions); + std::string item; + + bounds.clear(); + + while (std::getline(ss, item, ',')) + { + bounds.push_back(static_cast(std::atoi(item.c_str()))); + } +} + +static bool dimensionsToLabels( + const std::string& labelStr, + UnionCaseLabelSeq& labels) +{ + std::stringstream ss(labelStr); + std::string item; + bool def = false; + + labels.clear(); + while (std::getline(ss, item, ',')) + { + if (item == DEFAULT) + { + def = true; + } + else + { + labels.push_back(static_cast(std::stol(item.c_str()))); + } + } + + return def; +} + +DynamicType::_ref_type XMLParser:: parseXMLMemberDynamicType( + tinyxml2::XMLElement* p_root) +{ + /* + + + + + + + + + + + + */ + if (p_root == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing member: Node not found."); + return {}; + } + + const char* memberType = p_root->Attribute(TYPE); + const char* memberName = p_root->Attribute(NAME); + bool isArray = false; + + if (memberName == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing member name: Not found."); + return {}; + } + + if (memberType == nullptr) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing member type: Not found."); + return {}; + } + + const char* memberArray = p_root->Attribute(ARRAY_DIMENSIONS); + if (memberArray != nullptr) + { + isArray = true; + } + + if (strcmp(memberType, NON_BASIC_TYPE) == 0) + { + const char* memberNonBasicTypeName = p_root->Attribute(NON_BASIC_TYPE_NAME); + if (memberNonBasicTypeName != nullptr) + { + memberType = memberNonBasicTypeName; + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing member type: Not found."); + return {}; + } + } + + DynamicType::_ref_type member; + DynamicTypeBuilderFactory::_ref_type factory {DynamicTypeBuilderFactory::get_instance()}; + + const char* memberSequence = p_root->Attribute(SEQ_MAXLENGTH); + if (memberSequence != nullptr) + { + /* + In sequences allowed formats are (complex format includes the basic): + sequence,2> + + + + In this example, inner sequence's name is ignored and can be omited. + */ + DynamicType::_ref_type content_type {getDiscriminatorTypeBuilder(memberType)}; + if (!content_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing sequence element type: Cannot be recognized: " << memberType); + return {}; + } + + uint32_t length {0}; + try + { + length = static_cast(std::stoul(memberSequence)); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing member sequence length in line " << p_root->GetLineNum()); + return {}; + } + + if (!isArray) + { + DynamicTypeBuilder::_ref_type inner_builder{factory->create_sequence_type(content_type, length)}; + if (nullptr != inner_builder) + { + member = inner_builder->build(); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing sequence element type: Cannot recognize inner content of member: " << + memberType); + return {}; + } + } + else + { + DynamicTypeBuilder::_ref_type inner_builder{factory->create_sequence_type(content_type, length)}; + if (nullptr != inner_builder) + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type sub_builder{factory->create_array_type(inner_builder->build(), bounds)}; + if (nullptr != sub_builder) + { + member = sub_builder->build(); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing sequence element type: Cannot recognize inner content of member: " << + memberType); + return {}; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing sequence element type: Cannot recognize inner content of member: " << + memberType); + return {}; + } + } + } + else if (p_root->Attribute(MAP_MAXLENGTH) != nullptr) + { + /* + In maps allowed formats are (complex format includes the basic): + map, map,2> + + + + + + + + + + + + + In this example, inner maps names are ignored and can be omited. + */ + // Parse key + + //const char* keyType = p_root->Attribute(KEY); + DynamicType::_ref_type key_type; + const char* memberMapKeyType = p_root->Attribute(MAP_KEY_TYPE); + if (memberMapKeyType != nullptr) + { + key_type = getDiscriminatorTypeBuilder(memberMapKeyType); + if (!key_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing map's key element type: Cannot be recognized."); + return {}; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing key_type element: Not found."); + return {}; + } + + // Parse value + DynamicType::_ref_type value_type; + if (memberType != nullptr) + { + value_type = getDiscriminatorTypeBuilder(memberType); + if (!value_type) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing map's value element type: Cannot be recognized."); + return {}; + } + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Error parsing value_value element: Not found."); + return {}; + } + + const char* lengthStr = p_root->Attribute(MAP_MAXLENGTH); + uint32_t length {0}; + try + { + length = static_cast(std::stoul(lengthStr)); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing map member sequence length in line " << p_root->GetLineNum()); + return {}; + } + + if (!isArray) + { + member = factory->create_map_type(key_type, value_type, length)->build(); + } + else + { + DynamicTypeBuilder::_ref_type inner_builder {factory->create_map_type(key_type, value_type, + length)}; + if (!inner_builder) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing map member type: `create_map_type` failed for key=`" << key_type << + "`, value=`" << value_type << "`, length=`" << length << "`."); + return {}; + } + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + inner_builder->build(), + bounds); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, BOOLEAN, BOOLEAN_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_BOOLEAN); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_BOOLEAN), + bounds); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, CHAR, CHAR_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_CHAR8); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_CHAR8), + bounds); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, WCHAR, WCHAR_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_CHAR16); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_CHAR16), + bounds); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, TBYTE, TBYTE_len) == 0 + || strncmp(memberType, OCTET, OCTET_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_BYTE); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_BYTE), + bounds); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, UINT8, UINT8_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_UINT8); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_UINT8), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, INT8, INT8_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_INT8); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_INT8), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, SHORT, SHORT_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_INT16); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_INT16), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, LONG, LONG_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_INT32); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_INT32), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, ULONG, ULONG_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_UINT32); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_UINT32), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, USHORT, USHORT_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_UINT16); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_UINT16), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, LONGLONG, LONGLONG_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_INT64); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_INT64), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, ULONGLONG, ULONGLONG_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_UINT64); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_UINT64), + bounds); + + if (nullptr != builder) + { + member = builder->build(); + } + else + { + member = nullptr; + } + } + } + else if (strncmp(memberType, FLOAT, FLOAT_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_FLOAT32); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_FLOAT32), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, DOUBLE, DOUBLE_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_FLOAT64); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_FLOAT64), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, LONGDOUBLE, LONGDOUBLE_len) == 0) + { + if (!isArray) + { + member = factory->get_primitive_type(TK_FLOAT128); + } + else + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + factory->get_primitive_type(TK_FLOAT128), + bounds); + + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else if (strncmp(memberType, STRING, STRING_len) == 0) + { + const char* boundStr = p_root->Attribute(STR_MAXLENGTH); + uint32_t bound = static_cast(LENGTH_UNLIMITED); + + if (nullptr != boundStr) + { + try + { + bound = static_cast(std::stoul(boundStr)); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing alias type bound: '" << STR_MAXLENGTH << "' out of bounds."); + return {}; + } + } + + DynamicTypeBuilder::_ref_type string_builder = factory->create_string_type(bound); + + if (!isArray) + { + member = string_builder->build(); + } + else + { + std::vector boundsArray; + dimensionsToArrayBounds(memberArray, boundsArray); + DynamicTypeBuilder::_ref_type builder_ = factory->create_array_type(string_builder->build(), boundsArray); + if (nullptr != builder_) + { + member = builder_->build(); + } + else + { + member = nullptr; + } + } + } + else if (strncmp(memberType, WSTRING, WSTRING_len) == 0) + { + const char* boundStr = p_root->Attribute(STR_MAXLENGTH); + uint32_t bound = static_cast(LENGTH_UNLIMITED); + + if (nullptr != boundStr) + { + try + { + bound = static_cast(std::stoul(boundStr)); + } + catch (const std::exception&) + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Error parsing alias type bound: '" << STR_MAXLENGTH << "' out of bounds."); + return {}; + } + } + + DynamicTypeBuilder::_ref_type wstring_builder = factory->create_wstring_type(bound); + + if (!isArray) + { + member = wstring_builder->build(); + } + else + { + std::vector boundsArray; + dimensionsToArrayBounds(memberArray, boundsArray); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + wstring_builder->build(), + boundsArray); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + else // Complex type? + { + DynamicTypeBuilder::_ref_type type_builder; + XMLProfileManager::getDynamicTypeBuilderByName(type_builder, memberType); + DynamicType::_ref_type type; + if (nullptr != type_builder) + { + type = type_builder->build(); + } + else + { + type = nullptr; + } + + if (!isArray) + { + member = type; + } + else if (type) + { + std::vector bounds; + dimensionsToArrayBounds(memberArray, bounds); + DynamicTypeBuilder::_ref_type builder = factory->create_array_type( + type, + bounds); + member = nullptr; + if (nullptr != builder) + { + member = builder->build(); + } + } + } + + if (!member) + { + if (!isArray) + { + EPROSIMA_LOG_ERROR(XMLPARSER, "Failed creating " << memberType << ": " << (memberName ? memberName : "")); + } + else + { + EPROSIMA_LOG_ERROR(XMLPARSER, + "Failed creating " << memberType << " array: " << (memberName ? memberName : "")); + } + return {}; + } + + return member; +} + +DynamicType::_ref_type XMLParser::parseXMLMemberDynamicType( + tinyxml2::XMLElement* p_root, + DynamicTypeBuilder::_ref_type& builder, + MemberId mId) +{ + return parseXMLMemberDynamicType(p_root, builder, mId, ""); +} + +DynamicType::_ref_type XMLParser::parseXMLMemberDynamicType( + tinyxml2::XMLElement* p_root, + DynamicTypeBuilder::_ref_type& builder, + MemberId mId, + const std::string& values) +{ + DynamicType::_ref_type member {parseXMLMemberDynamicType(p_root)}; + + if (!member) + { + return {}; + } + + const char* memberName = p_root->Attribute(NAME); + + MemberDescriptor::_ref_type md {traits::make_shared()}; + md->id(mId); + md->name(memberName); + md->type(member); + + if (memberName != nullptr && !values.empty()) + { + UnionCaseLabelSeq labels; + bool defaultLabel = dimensionsToLabels(values, labels); + + md->label(labels); + md->is_default_label(defaultLabel); + } + + //{{{ Check @key annotation + const char* memberTopicKey = p_root->Attribute(KEY); + + if (memberTopicKey != nullptr && strncmp(memberTopicKey, "true", 5) == 0) + { + md->is_key(true); + } + //}}} + + + builder->add_member(md); + + return member; +} + +XMLP_ret XMLParser::parseXMLDynamicTypes( + tinyxml2::XMLElement& types) +{ + XMLP_ret ret = XMLP_ret::XML_OK; + ret = parseDynamicTypes(&types); + return ret; +} + +XMLP_ret XMLParser::parseDynamicTypes( + tinyxml2::XMLElement* p_root) +{ + return parseXMLTypes(p_root); +} + +XMLP_ret XMLParser::loadXMLDynamicTypes( + tinyxml2::XMLElement& xmlDoc) +{ + return parseXMLDynamicTypes(xmlDoc); +} diff --git a/test/unittest/xmlparser/XMLParserTests.cpp b/test/unittest/xmlparser/XMLParserTests.cpp index 8b9ff17d57b..71ee139344a 100644 --- a/test/unittest/xmlparser/XMLParserTests.cpp +++ b/test/unittest/xmlparser/XMLParserTests.cpp @@ -78,6 +78,19 @@ TEST_F(XMLParserTests, regressions) EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/20608_profile_bin.xml", root)); EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/20610_profile_bin.xml", root)); EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/20732_profile_bin.xml", root)); +<<<<<<< HEAD +======= + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/21153_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/21154_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/21181_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/21223_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/21334_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/21856_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/22054_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/22101_profile_bin.xml", root)); + EXPECT_EQ(XMLP_ret::XML_ERROR, XMLParser::loadXML("regressions/22535_profile_bin.xml", root)); + Log::Flush(); +>>>>>>> c0e7929f (Fix null-dereference in `parseXMLMemberDynamicType` (#5565)) } TEST_F(XMLParserTests, NoFile) diff --git a/test/unittest/xmlparser/regressions/22535_profile_bin.xml b/test/unittest/xmlparser/regressions/22535_profile_bin.xml new file mode 100644 index 00000000000..096e214b223 --- /dev/null +++ b/test/unittest/xmlparser/regressions/22535_profile_bin.xml @@ -0,0 +1 @@ +=:�>>" />>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>" />>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>" />>>" />>>" />>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�:�:�:�:�:�:�:�:�>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�:�>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>" />>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�:�:�:�:�:�:�:�:�>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�:�:�:�:�:�:�:�:�>>" />>�lfil"�� "��/>>�lfil"�� "��/>>>" />>>" />>�lfil"�� "��/>>>" />>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�>>>�lfil"�� "��/>" />>�lfil"��/>" />:trans�:�:�:�/ \ No newline at end of file