diff --git a/CMakeLists.txt b/CMakeLists.txt index 975d28dcca4..22c14e28e68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,7 +373,26 @@ endif() ############################################################################### # Tools default setup ############################################################################### -option(COMPILE_TOOLS "Build tools" ON) +if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine + OUTPUT_VARIABLE COMPILER_MACHINE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(COMPILER_MACHINE MATCHES "mingw") + message(STATUS "Using MinGW compiler.") + option(COMPILE_TOOLS "Build tools" OFF) + add_definitions(-DMINGW_COMPILER=1) + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -Wno-attributes -Wno-stringop-overread -Wno-builtin-macro-redefined -Wno-cast-function-type -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function -Wno-missing-field-initializers") + target_link_libraries(fastdds PUBLIC ws2_32 mswsock) + else() + message(STATUS "Using a GNU compiler on Windows but not MinGW.") + endif() +else() + message(STATUS "Not using a GNU compiler on Windows.") + option(COMPILE_TOOLS "Build tools" ON) +endif() if(EPROSIMA_BUILD) set(COMPILE_TOOLS ON) diff --git a/include/fastdds/fastdds_dll.hpp b/include/fastdds/fastdds_dll.hpp new file mode 100644 index 00000000000..e98dcfe2e17 --- /dev/null +++ b/include/fastdds/fastdds_dll.hpp @@ -0,0 +1,82 @@ +// Copyright 2016 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. + +/** + * @file fastdds_dll.hpp + * + */ + +#ifndef FASTDDS_FASTDDS_DLL_H +#define FASTDDS_FASTDDS_DLL_H + +#include + +// normalize macros +#if !defined(FASTDDS_DYN_LINK) && !defined(FASTDDS_STATIC_LINK) \ + && !defined(EPROSIMA_ALL_DYN_LINK) && !defined(EPROSIMA_ALL_STATIC_LINK) +#define FASTDDS_STATIC_LINK +#endif // if !defined(FASTDDS_DYN_LINK) && !defined(FASTDDS_STATIC_LINK) && !defined(EPROSIMA_ALL_DYN_LINK) && !defined(EPROSIMA_ALL_STATIC_LINK) + +#if defined(EPROSIMA_ALL_DYN_LINK) && !defined(FASTDDS_DYN_LINK) +#define FASTDDS_DYN_LINK +#endif // if defined(EPROSIMA_ALL_DYN_LINK) && !defined(FASTDDS_DYN_LINK) + +#if defined(FASTDDS_DYN_LINK) && defined(FASTDDS_STATIC_LINK) +#error Must not define both FASTDDS_DYN_LINK and FASTDDS_STATIC_LINK +#endif // if defined(FASTDDS_DYN_LINK) && defined(FASTDDS_STATIC_LINK) + +#if defined(EPROSIMA_ALL_NO_LIB) && !defined(FASTDDS_NO_LIB) +#define FASTDDS_NO_LIB +#endif // if defined(EPROSIMA_ALL_NO_LIB) && !defined(FASTDDS_NO_LIB) + +// enable dynamic linking + +#if defined(_WIN32) +#if defined(EPROSIMA_ALL_DYN_LINK) || defined(FASTDDS_DYN_LINK) +#if defined(MINGW_COMPILER) + #if defined(fastdds_EXPORTS) + #define FASTDDS_EXPORTED_API __declspec( dllexport ) + #else + #define FASTDDS_EXPORTED_API __attribute__((visibility("default"))) + #endif // FASTDDS_SOURCE +#else + #if defined(fastdds_EXPORTS) + #define FASTDDS_EXPORTED_API __declspec( dllexport ) + #else + #define FASTDDS_EXPORTED_API __declspec( dllimport ) + #endif // FASTDDS_SOURCE +#endif // if defined(MINGW_COMPILER) +#else +#define FASTDDS_EXPORTED_API +#endif // if defined(EPROSIMA_ALL_DYN_LINK) || defined(FASTDDS_DYN_LINK) +#else +#define FASTDDS_EXPORTED_API +#endif // _WIN32 + +// Auto linking. + +#if !defined(FASTDDS_SOURCE) && !defined(EPROSIMA_ALL_NO_LIB) \ + && !defined(FASTDDS_NO_LIB) + +// Set properties. +#define EPROSIMA_LIB_NAME fastdds + +#if defined(EPROSIMA_ALL_DYN_LINK) || defined(FASTDDS_DYN_LINK) +#define EPROSIMA_DYN_LINK +#endif // if defined(EPROSIMA_ALL_DYN_LINK) || defined(FASTDDS_DYN_LINK) + +#include +#endif // auto-linking disabled + +#endif // FASTDDS_FASTDDS_DLL_H diff --git a/include/fastrtps/utils/TimedMutex.hpp b/include/fastrtps/utils/TimedMutex.hpp index d20fae9cb4a..84d4b457678 100644 --- a/include/fastrtps/utils/TimedMutex.hpp +++ b/include/fastrtps/utils/TimedMutex.hpp @@ -26,6 +26,8 @@ #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 193632528 #include +#elif defined(MINGW_COMPILER) +#include #else #include extern int clock_gettime( @@ -47,6 +49,9 @@ namespace fastrtps { #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 193632528 using TimedMutex = std::timed_mutex; using RecursiveTimedMutex = std::recursive_timed_mutex; +#elif defined(MINGW_COMPILER) +using TimedMutex = std::timed_mutex; +using RecursiveTimedMutex = std::recursive_timed_mutex; #else class TimedMutex { diff --git a/src/cpp/fastdds/xtypes/serializers/json/dynamic_data_json.cpp b/src/cpp/fastdds/xtypes/serializers/json/dynamic_data_json.cpp new file mode 100644 index 00000000000..d4253134a34 --- /dev/null +++ b/src/cpp/fastdds/xtypes/serializers/json/dynamic_data_json.cpp @@ -0,0 +1,1012 @@ +// Copyright 2024 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 +#ifndef MINGW_COMPILER + #include +#endif // ifndef MINGW_COMPILER +#include +#include +#include + +#include + +#include + +#include "dynamic_data_json.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "../../dynamic_types/DynamicDataImpl.hpp" +#include "../../dynamic_types/DynamicTypeImpl.hpp" +#include "../../dynamic_types/DynamicTypeMemberImpl.hpp" +#include "../../dynamic_types/MemberDescriptorImpl.hpp" +#include "../../dynamic_types/TypeDescriptorImpl.hpp" + +namespace eprosima { +namespace fastdds { +namespace dds { + +ReturnCode_t json_serialize( + const traits::ref_type& data, + nlohmann::json& output, + DynamicDataJsonFormat format) noexcept +{ + if (nullptr == data) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Encountered null data value while performing DynamicData to JSON serialization."); + return RETCODE_BAD_PARAMETER; + } + + switch (data->type()->get_kind()) + { + case TK_STRUCTURE: + { + DynamicTypeMembersById members; + ReturnCode_t ret = data->type()->get_all_members(members); + if (RETCODE_OK != ret) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing structure to JSON: get_all_members failed."); + return ret; + } + for (const auto& it : members) + { + if (RETCODE_OK != (ret = json_serialize_member(data, it.second, output, format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing structure member '" << it.second->get_name() << + "' to JSON."); + break; + } + } + return ret; + } + default: + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Only structs are supported by json_serialize method."); + return RETCODE_BAD_PARAMETER; + } + } +} + +ReturnCode_t json_serialize_member( + const traits::ref_type& data, + const traits::ref_type& type_member, + nlohmann::json& output, + DynamicDataJsonFormat format) noexcept +{ + MemberDescriptorImpl& member_desc = + traits::narrow(type_member)->get_descriptor(); + + return json_serialize_member(data, type_member->get_id(), + traits::narrow( + member_desc.type())->resolve_alias_enclosed_type()->get_kind(), + type_member->get_name().to_string(), output, format); +} + +ReturnCode_t json_serialize_member( + const traits::ref_type& data, + MemberId member_id, + TypeKind member_kind, + const std::string& member_name, + nlohmann::json& output, + DynamicDataJsonFormat format) noexcept +{ + switch (member_kind) + { + case TK_NONE: + case TK_BOOLEAN: + case TK_BYTE: + case TK_INT8: + case TK_INT16: + case TK_INT32: + case TK_INT64: + case TK_UINT8: + case TK_UINT16: + case TK_UINT32: + case TK_UINT64: + case TK_FLOAT32: + case TK_FLOAT64: + case TK_FLOAT128: + case TK_CHAR8: + case TK_CHAR16: + case TK_STRING8: + case TK_STRING16: + case TK_ENUM: + { + return json_serialize_basic_member(data, member_id, member_kind, member_name, output, format); + } + case TK_STRUCTURE: + case TK_BITSET: + { + std::string kind_str = (member_kind == TK_STRUCTURE) ? "structure" : "bitset"; + traits::ref_type st_data = + traits::narrow(data->loan_value(member_id)); + if (nullptr == st_data) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing " << kind_str << " member to JSON: loan_value failed."); + return RETCODE_BAD_PARAMETER; + } + + // Fill JSON object with loaned value + nlohmann::json j_struct; + DynamicTypeMembersById members; + ReturnCode_t ret = st_data->enclosing_type()->get_all_members(members); + if (RETCODE_OK != ret) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing " << kind_str << + " member to JSON: get_all_members failed."); + } + else + { + for (const auto& it : members) + { + if (RETCODE_OK != (ret = json_serialize_member(st_data, it.second, j_struct, format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing " << kind_str << " member '" << it.second->get_name() << + "' to JSON."); + break; + } + } + // Insert into JSON object if all members were serialized successfully + if (RETCODE_OK == ret) + { + json_insert(member_name, j_struct, output); + } + } + + // Return loaned value + // NOTE: this should always be done, even if something went wrong before + ReturnCode_t ret_return_loan; + if (RETCODE_OK != (ret_return_loan = data->return_loaned_value(st_data))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while returning " << kind_str << " loaned value."); + } + // Give priority to prior error if occurred + return RETCODE_OK != ret ? ret : ret_return_loan; + } + case TK_UNION: + { + traits::ref_type st_data = + traits::narrow(data->loan_value(member_id)); + if (nullptr == st_data) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing union member to JSON: loan_value failed."); + return RETCODE_BAD_PARAMETER; + } + + // Fill JSON object with loaned value + nlohmann::json j_union; + ReturnCode_t ret = RETCODE_OK; + MemberId selected_member = st_data->selected_union_member(); + + if (MEMBER_ID_INVALID == selected_member) + { + // No member selected, insert empty JSON object + json_insert(member_name, j_union, output); + } + else + { + DynamicTypeMember::_ref_type active_type_member; + ret = st_data->enclosing_type()->get_member(active_type_member, selected_member); + if (RETCODE_OK != ret) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing union member to JSON: get_member failed."); + } + else + { + if (RETCODE_OK == (ret = json_serialize_member(st_data, active_type_member, j_union, format))) + { + json_insert(member_name, j_union, output); + } + } + } + + // Return loaned value + // NOTE: this should always be done, even if something went wrong before + ReturnCode_t ret_return_loan; + if (RETCODE_OK != (ret_return_loan = data->return_loaned_value(st_data))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while returning union loaned value."); + } + // Give priority to prior error if occurred + return RETCODE_OK != ret ? ret : ret_return_loan; + } + case TK_SEQUENCE: + case TK_ARRAY: + { + std::string kind_str = (member_kind == TK_SEQUENCE) ? "sequence" : "array"; + traits::ref_type st_data = + traits::narrow(data->loan_value(member_id)); + if (nullptr == st_data) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing " << kind_str << " member to JSON: loan_value failed."); + return RETCODE_BAD_PARAMETER; + } + + // Fill JSON object with loaned value + ReturnCode_t ret = json_serialize_collection(st_data, member_name, output, format); + + // Return loaned value + // NOTE: this should always be done, even if something went wrong before + ReturnCode_t ret_return_loan; + if (RETCODE_OK != (ret_return_loan = data->return_loaned_value(st_data))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while returning " << kind_str << " loaned value."); + } + // Give priority to prior error if occurred + return RETCODE_OK != ret ? ret : ret_return_loan; + } + case TK_MAP: + { + traits::ref_type st_data = + traits::narrow(data->loan_value(member_id)); + if (nullptr == st_data) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing map member to JSON: loan_value failed."); + return RETCODE_BAD_PARAMETER; + } + + ReturnCode_t ret = RETCODE_OK; + nlohmann::json j_map; + const TypeDescriptorImpl& map_desc = st_data->enclosing_type()->get_descriptor(); + traits::ref_type key_type = traits::narrow( + map_desc.key_element_type())->resolve_alias_enclosed_type(); + traits::ref_type value_type = traits::narrow( + map_desc.element_type())->resolve_alias_enclosed_type(); + + std::map key_to_id; + if (RETCODE_OK != (ret = st_data->get_keys(key_to_id))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing map member to JSON: get_keys failed."); + } + + if (RETCODE_OK == ret) + { + std::map id_to_key; + for (const auto& it : key_to_id) + { + id_to_key[it.second] = it.first; + } + assert(id_to_key.size() == key_to_id.size()); + + uint32_t size = st_data->get_item_count(); + assert(size == key_to_id.size()); + for (uint32_t i = 0; i < size; ++i) + { + MemberId id = st_data->get_member_id_at_index(i); + if (MEMBER_ID_INVALID == id) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing map member's member to JSON: invalid member id."); + ret = RETCODE_BAD_PARAMETER; + break; + } + + auto it = id_to_key.find(id); + if (it == id_to_key.end()) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing map member's member to JSON: key not found."); + ret = RETCODE_BAD_PARAMETER; + break; + } + + if (RETCODE_OK != + (ret = + json_serialize_member(st_data, id, value_type->get_kind(), it->second, j_map, + format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing map member's member to JSON."); + break; + } + } + } + + // Insert into JSON object if all members were serialized successfully + if (RETCODE_OK == ret) + { + json_insert(member_name, j_map, output); + } + + // Return loaned value + // NOTE: this should always be done, even if something went wrong before + ReturnCode_t ret_return_loan; + if (RETCODE_OK != (ret_return_loan = data->return_loaned_value(st_data))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while returning map loaned value."); + } + // Give priority to prior error if occurred + return RETCODE_OK != ret ? ret : ret_return_loan; + } + case TK_BITMASK: + { + traits::ref_type st_data = + traits::narrow(data->loan_value(member_id)); + if (nullptr == st_data) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing bitmask member to JSON: loan_value failed."); + return RETCODE_BAD_PARAMETER; + } + + ReturnCode_t ret = RETCODE_OK; + traits::ref_type bitmask_type = st_data->enclosing_type(); + const TypeDescriptorImpl& bitmask_desc = bitmask_type->get_descriptor(); + + auto bound = bitmask_desc.bound().at(0); + + if (format == DynamicDataJsonFormat::OMG) + { + if (9 > bound) + { + uint8_t value; + if (RETCODE_OK == (ret = st_data->get_uint8_value(value, MEMBER_ID_INVALID))) + { + json_insert(member_name, value, output); + } + } + else if (17 > bound) + { + uint16_t value; + if (RETCODE_OK == (ret = st_data->get_uint16_value(value, MEMBER_ID_INVALID))) + { + json_insert(member_name, value, output); + } + } + else if (33 > bound) + { + uint32_t value; + if (RETCODE_OK == (ret = st_data->get_uint32_value(value, MEMBER_ID_INVALID))) + { + json_insert(member_name, value, output); + } + } + else + { + uint64_t value; + if (RETCODE_OK == (ret = st_data->get_uint64_value(value, MEMBER_ID_INVALID))) + { + json_insert(member_name, value, output); + } + } + + if (RETCODE_OK != ret) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing bitmask member to JSON: failed to get value."); + } + } + else if (format == DynamicDataJsonFormat::EPROSIMA) + { + nlohmann::json bitmask_dict; + uint64_t u64_value{0}; // Auxiliar variable to check active bits afterwards + if (9 > bound) + { + uint8_t value; + if (RETCODE_OK == (ret = st_data->get_uint8_value(value, MEMBER_ID_INVALID))) + { + bitmask_dict["value"] = value; + bitmask_dict["binary"] = std::bitset<8>(value).to_string(); + u64_value = static_cast(value); + } + } + else if (17 > bound) + { + uint16_t value; + if (RETCODE_OK == (ret = st_data->get_uint16_value(value, MEMBER_ID_INVALID))) + { + bitmask_dict["value"] = value; + bitmask_dict["binary"] = std::bitset<16>(value).to_string(); + u64_value = static_cast(value); + } + } + else if (33 > bound) + { + uint32_t value; + if (RETCODE_OK == (ret = st_data->get_uint32_value(value, MEMBER_ID_INVALID))) + { + bitmask_dict["value"] = value; + bitmask_dict["binary"] = std::bitset<32>(value).to_string(); + u64_value = static_cast(value); + } + } + else + { + uint64_t value; + if (RETCODE_OK == (ret = st_data->get_uint64_value(value, MEMBER_ID_INVALID))) + { + bitmask_dict["value"] = value; + bitmask_dict["binary"] = std::bitset<64>(value).to_string(); + u64_value = value; + } + } + + if (RETCODE_OK != ret) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing bitmask member to JSON: failed to get value."); + } + else + { + // Check active bits + DynamicTypeMembersById bitmask_members; + if (RETCODE_OK != (ret = bitmask_type->get_all_members(bitmask_members))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing bitmask member to JSON: get_all_members failed."); + } + else + { + std::vector active_bits; + for (const auto& it : bitmask_members) + { + if (u64_value & (0x01ull << it.second->get_id())) + { + active_bits.push_back(it.second->get_name().to_string()); + } + } + bitmask_dict["active"] = active_bits; + + // Insert custom bitmask value + json_insert(member_name, bitmask_dict, output); + } + } + } + + // Return loaned value + // NOTE: this should always be done, even if something went wrong before + ReturnCode_t ret_return_loan; + if (RETCODE_OK != (ret_return_loan = data->return_loaned_value(st_data))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while returning bitmask loaned value."); + } + // Give priority to prior error if occurred + return RETCODE_OK != ret ? ret : ret_return_loan; + } + case TK_ALIAS: + { + // This should not happen, as this method should always be called with the enclosed type + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing member to JSON: unexpected TK_ALIAS kind."); + return RETCODE_BAD_PARAMETER; + } + default: + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing map member to JSON: unexpected kind " << member_kind << + " found."); + return RETCODE_BAD_PARAMETER; + } +} + +ReturnCode_t json_serialize_member( + const traits::ref_type& data, + MemberId member_id, + TypeKind member_kind, + nlohmann::json& output, + DynamicDataJsonFormat format) noexcept +{ + return json_serialize_member(data, member_id, member_kind, "", output, format); +} + +ReturnCode_t json_serialize_basic_member( + const traits::ref_type& data, + MemberId member_id, + TypeKind member_kind, + const std::string& member_name, + nlohmann::json& output, + DynamicDataJsonFormat format) noexcept +{ + switch (member_kind) + { + case TK_NONE: + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing basic member to JSON: unexpected TK_NONE kind."); + return RETCODE_BAD_PARAMETER; + } + case TK_BOOLEAN: + { + bool value; + ReturnCode_t ret = data->get_boolean_value(value, member_id); + if (RETCODE_OK == ret) + { + if (TK_BITSET == data->enclosing_type()->get_kind()) + { + json_insert(member_name, static_cast(value), output); + } + else + { + json_insert(member_name, value, output); + } + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_BOOLEAN member to JSON."); + } + return ret; + } + case TK_BYTE: + { + fastdds::rtps::octet value; + ReturnCode_t ret = data->get_byte_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_BYTE member to JSON."); + } + return ret; + } + case TK_INT8: + { + int8_t value; + ReturnCode_t ret = data->get_int8_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_INT8 member to JSON."); + } + return ret; + } + case TK_INT16: + { + int16_t value; + ReturnCode_t ret = data->get_int16_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_INT16 member to JSON."); + } + return ret; + } + case TK_INT32: + { + int32_t value; + ReturnCode_t ret = data->get_int32_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_INT32 member to JSON."); + } + return ret; + } + case TK_INT64: + { + int64_t value; + ReturnCode_t ret = data->get_int64_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_INT64 member to JSON."); + } + return ret; + } + case TK_UINT8: + { + uint8_t value; + ReturnCode_t ret = data->get_uint8_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_UINT8 member to JSON."); + } + return ret; + } + case TK_UINT16: + { + uint16_t value; + ReturnCode_t ret = data->get_uint16_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_UINT16 member to JSON."); + } + return ret; + } + case TK_UINT32: + { + uint32_t value; + ReturnCode_t ret = data->get_uint32_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_UINT32 member to JSON."); + } + return ret; + } + case TK_UINT64: + { + uint64_t value; + ReturnCode_t ret = data->get_uint64_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_UINT64 member to JSON."); + } + return ret; + } + case TK_FLOAT32: + { + float value; + ReturnCode_t ret = data->get_float32_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_FLOAT32 member to JSON."); + } + return ret; + } + case TK_FLOAT64: + { + double value; + ReturnCode_t ret = data->get_float64_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_FLOAT64 member to JSON."); + } + return ret; + } + case TK_FLOAT128: + { + long double value; + ReturnCode_t ret = data->get_float128_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_FLOAT128 member to JSON."); + } + return ret; + } + case TK_CHAR8: + { + char value; + ReturnCode_t ret = data->get_char8_value(value, member_id); + if (RETCODE_OK == ret) + { + std::string aux_string_value({value}); + json_insert(member_name, aux_string_value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_CHAR8 member to JSON."); + } + return ret; + } + case TK_CHAR16: + { + wchar_t value; + ReturnCode_t ret = data->get_char16_value(value, member_id); + if (RETCODE_OK == ret) + { + // Insert UTF-8 converted value +#if defined(MINGW_COMPILER) + std::wstring aux_wstring_value({value}); + std::string utf8_value; + int size_needed = std::wcstombs(nullptr, aux_wstring_value.data(), 0); + if (size_needed > 0) + { + utf8_value.resize(size_needed); + std::wcstombs(&utf8_value[0], aux_wstring_value.data(), size_needed); + } +#else + std::wstring aux_wstring_value({value}); + std::wstring_convert> converter; + std::string utf8_value = converter.to_bytes(aux_wstring_value); + +#endif // defined(MINGW_COMPILER) + json_insert(member_name, utf8_value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_CHAR16 member to JSON."); + } + return ret; + } + case TK_STRING8: + { + std::string value; + ReturnCode_t ret = data->get_string_value(value, member_id); + if (RETCODE_OK == ret) + { + json_insert(member_name, value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_STRING8 member to JSON."); + } + return ret; + } + case TK_STRING16: + { + std::wstring value; + ReturnCode_t ret = data->get_wstring_value(value, member_id); + if (RETCODE_OK == ret) + { + // Insert UTF-8 converted value +#ifdef MINGW_COMPILER + std::string utf8_value; + int size_needed = std::wcstombs(nullptr, value.data(), 0); + if (size_needed > 0) + { + utf8_value.resize(size_needed); + std::wcstombs(&utf8_value[0], value.data(), size_needed); + } +#else + std::wstring_convert> converter; + std::string utf8_value = converter.to_bytes(value); +#endif // defined(MINGW_COMPILER) + json_insert(member_name, utf8_value, output); + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_STRING16 member to JSON."); + } + return ret; + } + case TK_ENUM: + { + int32_t value; + ReturnCode_t ret = data->get_int32_value(value, member_id); + if (RETCODE_OK != ret) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_ENUM member to JSON."); + return ret; + } + + // Get enumeration type to obtain the names of the different values + // NOTE: a different approach is required for collections and other "holder" types (e.g. structures), + // as unlike with DynamicData::loan_value or DynamicData::get_X_value, DynamicData::get_descriptor method + // is not meant to work with sequences nor arrays according to XTypes standard. + traits::ref_type enum_type; + TypeKind holder_kind = data->enclosing_type()->get_kind(); + if (TK_ARRAY == holder_kind || TK_SEQUENCE == holder_kind) + { + const TypeDescriptorImpl& collection_descriptor = data->enclosing_type()->get_descriptor(); + enum_type = collection_descriptor.element_type(); + } + else + { + MemberDescriptor::_ref_type enum_desc{traits::make_shared()}; + if (RETCODE_OK != (ret = data->get_descriptor(enum_desc, member_id))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing TK_ENUM member to JSON: get_descriptor failed."); + return ret; + } + enum_type = enum_desc->type(); + } + + DynamicTypeMembersByName all_members; + if (RETCODE_OK != + (ret = + traits::narrow(enum_type)->resolve_alias_enclosed_type()-> + get_all_members_by_name(all_members))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing TK_ENUM member to JSON: get_all_members_by_name failed."); + return ret; + } + + ObjectName name; + ret = RETCODE_BAD_PARAMETER; + for (const auto& it : all_members) + { + MemberDescriptorImpl& enum_member_desc = traits::narrow( + it.second)->get_descriptor(); + if (enum_member_desc.default_value() == std::to_string(value)) + { + name = it.first; + assert(name == it.second->get_name()); + ret = RETCODE_OK; + break; + } + } + if (RETCODE_OK == ret) + { + if (format == DynamicDataJsonFormat::OMG) + { + json_insert(member_name, name, output); + } + else if (format == DynamicDataJsonFormat::EPROSIMA) + { + nlohmann::json enum_dict = {{"name", name}, {"value", value}}; + json_insert(member_name, enum_dict, output); + } + } + else + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing TK_ENUM member to JSON: enum value not found."); + } + return ret; + } + default: + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing basic member to JSON: unexpected kind " << member_kind << + " found."); + return RETCODE_BAD_PARAMETER; + } +} + +ReturnCode_t json_serialize_collection( + const traits::ref_type& data, + const std::string& member_name, + nlohmann::json& output, + DynamicDataJsonFormat format) noexcept +{ + ReturnCode_t ret = RETCODE_OK; + if (data->enclosing_type()->get_kind() == TK_SEQUENCE) + { + const TypeDescriptorImpl& descriptor = data->enclosing_type()->get_descriptor(); + + auto count = data->get_item_count(); + nlohmann::json j_array = nlohmann::json::array(); + for (uint32_t index = 0; index < count; ++index) + { + if (RETCODE_OK != + (ret = + json_serialize_member(data, static_cast(index), + traits::narrow(descriptor.element_type())->resolve_alias_enclosed_type() + ->get_kind(), j_array, + format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing sequence collection to JSON."); + break; + } + } + if (RETCODE_OK == ret) + { + json_insert(member_name, j_array, output); + } + } + else + { + const TypeDescriptorImpl& descriptor = data->enclosing_type()->get_descriptor(); + + const BoundSeq& bounds = descriptor.bound(); + nlohmann::json j_array = nlohmann::json::array(); + unsigned int index = 0; + if (RETCODE_OK != (ret = json_serialize_array(data, traits::narrow( + descriptor.element_type())->resolve_alias_enclosed_type()->get_kind(), index, bounds, j_array, + format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing array collection to JSON."); + } + else + { + json_insert(member_name, j_array, output); + } + } + return ret; +} + +ReturnCode_t json_serialize_array( + const traits::ref_type& data, + TypeKind member_kind, + unsigned int& index, + const std::vector& bounds, + nlohmann::json& j_array, + DynamicDataJsonFormat format) noexcept +{ + assert(j_array.is_array()); + ReturnCode_t ret = RETCODE_OK; + if (bounds.size() == 1) + { + for (unsigned int i = 0; i < bounds[0]; ++i) + { + if (RETCODE_OK != + (ret = + json_serialize_member(data, static_cast(index++), member_kind, j_array, + format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing array element to JSON."); + break; + } + } + } + else + { + for (unsigned int i = 0; i < bounds[0]; ++i) + { + nlohmann::json inner_array = nlohmann::json::array(); + if (RETCODE_OK != + (ret = + json_serialize_array(data, member_kind, index, + std::vector(bounds.begin() + 1, bounds.end()), inner_array, format))) + { + EPROSIMA_LOG_ERROR(XTYPES_UTILS, + "Error encountered while serializing array's array element to JSON."); + break; + } + j_array.push_back(inner_array); + } + } + return ret; +} + +template +void json_insert( + const std::string& key, + const T& value, + nlohmann::json& j) +{ + if (j.is_array()) + { + j.push_back(value); + } + else + { + j[key] = value; + } +} + +} // namespace dds +} // namespace fastdds +} // namespace eprosima diff --git a/src/cpp/utils/SystemInfo.cpp b/src/cpp/utils/SystemInfo.cpp index 8aab32dbb9d..2b9e1651d06 100644 --- a/src/cpp/utils/SystemInfo.cpp +++ b/src/cpp/utils/SystemInfo.cpp @@ -156,9 +156,18 @@ ReturnCode_t SystemInfo::get_username( bool SystemInfo::file_exists( const std::string& filename) { +#ifdef _WIN32 + // modify for mingw + DWORD fileAttributes = GetFileAttributesA(filename.c_str()); + if (fileAttributes == INVALID_FILE_ATTRIBUTES) + { + return false; + } + return !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY); +#else struct stat s; - // Check existence and that it is a regular file (and not a folder) return (stat(filename.c_str(), &s) == 0 && s.st_mode & S_IFREG); +#endif // ifdef _WIN32 } bool SystemInfo::wait_for_file_closure( diff --git a/src/cpp/utils/TimedConditionVariable.cpp b/src/cpp/utils/TimedConditionVariable.cpp index b9aae00039d..ea63ce3ae47 100644 --- a/src/cpp/utils/TimedConditionVariable.cpp +++ b/src/cpp/utils/TimedConditionVariable.cpp @@ -48,12 +48,28 @@ int clock_gettime(int, struct timespec* tv) tv->tv_sec = (long)(hnsTime.QuadPart / HNS_PER_SEC); return 0; +<<<<<<< HEAD } */ #define exp7 10000000i64 //1E+7 //C-file part #define exp9 1000000000i64 //1E+9 #define w2ux 116444736000000000i64 //1.jan1601 to 1.jan1970 void unix_time(struct timespec* spec) +======= + } + */ +#ifdef MINGW_COMPILER + #define exp7 10000000LL //1E+7 //C-file part + #define exp9 1000000000LL //1E+9 + #define w2ux 116444736000000000LL //1.jan1601 to 1.jan1970 +#else + #define exp7 10000000i64 //1E+7 //C-file part + #define exp9 1000000000i64 //1E+9 + #define w2ux 116444736000000000i64 //1.jan1601 to 1.jan1970 +#endif // ifdef MINGW_COMPILER +void unix_time( + struct timespec* spec) +>>>>>>> 28b11cab (Support compiler MSYS2-MinGW (#5600)) { __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)& wintime); wintime -= w2ux; spec->tv_sec = wintime / exp7; diff --git a/src/cpp/utils/shared_memory/RobustExclusiveLock.hpp b/src/cpp/utils/shared_memory/RobustExclusiveLock.hpp index c7e67bf8b08..013adb0241a 100644 --- a/src/cpp/utils/shared_memory/RobustExclusiveLock.hpp +++ b/src/cpp/utils/shared_memory/RobustExclusiveLock.hpp @@ -17,6 +17,8 @@ #ifdef _MSC_VER #include +#elif defined(MINGW_COMPILER) +#include #else #include #endif // ifdef _MSC_VER @@ -165,6 +167,45 @@ class RobustExclusiveLock } } +#elif defined(MINGW_COMPILER) + static int open_and_lock_file( + const std::string& file_path, + bool* was_lock_created) + { + int test_exist; + auto ret = _sopen_s(&test_exist, file_path.c_str(), O_RDONLY, 0x0010, _S_IREAD | _S_IWRITE); + + if (ret == 0) + { + *was_lock_created = false; + return test_exist; + } + + int fd; + ret = _sopen_s(&fd, file_path.c_str(), O_CREAT | O_RDONLY, 0x0010, _S_IREAD | _S_IWRITE); + + if (ret != 0) + { + return -1; + } + + *was_lock_created = true; + + return fd; + } + + static void unlock_and_close( + int fd, + const std::string& name) + { + _close(fd); + + if (0 != std::remove(SharedDir::get_lock_path(name).c_str())) + { + EPROSIMA_LOG_WARNING(RTPS_TRANSPORT_SHM, "Failed to remove " << SharedDir::get_lock_path(name)); + } + } + #else static int open_and_lock_file( diff --git a/src/cpp/utils/shared_memory/RobustSharedLock.hpp b/src/cpp/utils/shared_memory/RobustSharedLock.hpp index 68f18316ebb..5819c3bd69b 100644 --- a/src/cpp/utils/shared_memory/RobustSharedLock.hpp +++ b/src/cpp/utils/shared_memory/RobustSharedLock.hpp @@ -17,6 +17,8 @@ #ifdef _MSC_VER #include +#elif defined(MINGW_COMPILER) +#include #else #include #endif // ifdef _MSC_VER @@ -230,6 +232,118 @@ class RobustSharedLock return lock_status; } +#elif defined(MINGW_COMPILER) + int open_and_lock_file( + const std::string& file_path, + bool* was_lock_created, + bool* was_lock_released) + { + int test_exist; + + // Try open exclusive + auto ret = _sopen_s(&test_exist, file_path.c_str(), _O_WRONLY, 0x0010, _S_IREAD | _S_IWRITE); + + if (ret == 0) + { + *was_lock_created = false; + + if (was_lock_released) + { + *was_lock_released = true; + } + + _close(test_exist); + } + else + { + // Try open shared + ret = _sopen_s(&test_exist, file_path.c_str(), _O_RDONLY, 0x0010, _S_IREAD | _S_IWRITE); + + if (ret == 0) + { + if (was_lock_released) + { + *was_lock_released = false; + } + + *was_lock_created = false; + + return test_exist; + } + else + { + if (was_lock_released) + { + *was_lock_released = true; + } + + *was_lock_created = true; + } + } + + int fd; + // Open or create shared + ret = _sopen_s(&fd, file_path.c_str(), O_CREAT | _O_RDONLY, 0x0010, _S_IREAD | _S_IWRITE); + + if (ret != 0) + { + char errmsg[1024]; + strerror_s(errmsg, sizeof(errmsg), errno); + throw std::runtime_error("failed to open/create " + file_path + " " + std::string(errmsg)); + } + + return fd; + } + + void unlock_and_close() + { + _close(fd_); + + test_lock(SharedDir::get_lock_path(name_), true); + } + + static LockStatus test_lock( + const std::string& file_path, + bool remove_if_unlocked = false) + { + LockStatus lock_status; + + int fd; + auto ret = _sopen_s(&fd, file_path.c_str(), _O_RDONLY, 0x0010, _S_IREAD | _S_IWRITE); + + if (ret == 0) + { + lock_status = LockStatus::NOT_LOCKED; + + _close(fd); + + // Lock exclusive + ret = _sopen_s(&fd, file_path.c_str(), _O_WRONLY, 0x0010, _S_IREAD | _S_IWRITE); + if (ret != 0) + { + lock_status = LockStatus::LOCKED; + } + else + { + _close(fd); + } + } + else + { + lock_status = LockStatus::OPEN_FAILED; + } + + if (lock_status == LockStatus::NOT_LOCKED && remove_if_unlocked) + { + if (0 != std::remove(file_path.c_str())) + { + EPROSIMA_LOG_WARNING(RTPS_TRANSPORT_SHM, "Failed to remove " << file_path); + } + } + + return lock_status; + } + #else int open_and_lock_file( diff --git a/thirdparty/filewatch/FileWatch.hpp b/thirdparty/filewatch/FileWatch.hpp index 8f4b6092b4f..9f8c63591e1 100644 --- a/thirdparty/filewatch/FileWatch.hpp +++ b/thirdparty/filewatch/FileWatch.hpp @@ -30,7 +30,9 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN -#define stat _stat +#ifndef MINGW_COMPILER + #define stat _stat // do not use stat in windows +#endif // ifndef MINGW_COMPILER #ifndef NOMINMAX #define NOMINMAX #endif @@ -404,7 +406,7 @@ namespace filewatch { std::ratio_multiply>( reinterpret_cast(&att.ftLastWriteTime)->QuadPart - base_.first.QuadPart); - if (bytes_returned == 0 || (current_time == last_write_time_) && current_size == last_size_ ) { + if (bytes_returned == 0 || ((current_time == last_write_time_) && current_size == last_size_ )) { break; }