Skip to content

Commit 7c69dd4

Browse files
Refs #22202. Support all types
Signed-off-by: Juan Lopez Fernandez <juanlopez@eprosima.com>
1 parent 267da35 commit 7c69dd4

5 files changed

Lines changed: 1118 additions & 193 deletions

File tree

src/cpp/fastdds/xtypes/serializers/json/dynamic_data_json.cpp

Lines changed: 135 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
#ifndef MINGW_COMPILER
1717
#include <codecvt>
1818
#endif // ifndef MINGW_COMPILER
19+
#include <cstdint>
1920
#include <iomanip>
2021
#include <iostream>
22+
#include <limits>
2123
#include <string>
2224

2325
#include <nlohmann/json.hpp>
@@ -266,6 +268,7 @@ ReturnCode_t json_serialize_member(
266268
}
267269
case TK_MAP:
268270
{
271+
// TODO: encapsulate all complex kinds serialization?
269272
traits<DynamicDataImpl>::ref_type st_data =
270273
traits<DynamicData>::narrow<DynamicDataImpl>(data->loan_value(member_id));
271274
if (nullptr == st_data)
@@ -364,6 +367,7 @@ ReturnCode_t json_serialize_member(
364367
traits<DynamicTypeImpl>::ref_type bitmask_type = st_data->enclosing_type();
365368
const TypeDescriptorImpl& bitmask_desc = bitmask_type->get_descriptor();
366369

370+
// Get the bitmask bound to determine the value precision
367371
auto bound = bitmask_desc.bound().at(0);
368372

369373
if (format == DynamicDataJsonFormat::OMG)
@@ -716,6 +720,14 @@ ReturnCode_t json_serialize_basic_member(
716720
ReturnCode_t ret = data->get_float128_value(value, member_id);
717721
if (RETCODE_OK == ret)
718722
{
723+
// Fail if value exceeds double limits, as JSON does not support long double
724+
if (value < std::numeric_limits<double>::lowest() ||
725+
value > std::numeric_limits<double>::max())
726+
{
727+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
728+
"Error encountered while serializing TK_FLOAT128 member to JSON: value out of range.");
729+
return RETCODE_BAD_PARAMETER;
730+
}
719731
json_insert(member_name, value, output);
720732
}
721733
else
@@ -746,20 +758,39 @@ ReturnCode_t json_serialize_basic_member(
746758
if (RETCODE_OK == ret)
747759
{
748760
// Insert UTF-8 converted value
749-
#if defined(MINGW_COMPILER)
750761
std::wstring aux_wstring_value({value});
751-
std::string utf8_value;
752-
int size_needed = std::wcstombs(nullptr, aux_wstring_value.data(), 0);
753-
if (size_needed > 0)
762+
std::string utf8_value("\0", 1);
763+
#if defined(MINGW_COMPILER)
764+
// WARNING: it is the user responsibility to set the appropiate UTF-8 locale before calling this method
765+
int size_needed = std::wcstombs(nullptr, aux_wstring_value.c_str(), 0);
766+
if (size_needed < 0)
767+
{
768+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
769+
"Error encountered while serializing TK_CHAR16 member to JSON: encountered invalid character.");
770+
return RETCODE_BAD_PARAMETER;
771+
}
772+
else if (size_needed > 0)
754773
{
755774
utf8_value.resize(size_needed);
756-
std::wcstombs(&utf8_value[0], aux_wstring_value.data(), size_needed);
775+
if (std::wcstombs(&utf8_value[0], aux_wstring_value.c_str(), size_needed) == static_cast<std::size_t>(-1))
776+
{
777+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
778+
"Error encountered while serializing TK_CHAR16 member to JSON: encountered invalid character.");
779+
return RETCODE_BAD_PARAMETER;
780+
}
757781
}
758782
#else
759-
std::wstring aux_wstring_value({value});
760783
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
761-
std::string utf8_value = converter.to_bytes(aux_wstring_value); // TODO: handle exception
762-
784+
try
785+
{
786+
utf8_value = converter.to_bytes(aux_wstring_value);
787+
}
788+
catch (const std::exception& e)
789+
{
790+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
791+
"Error encountered while serializing TK_CHAR16 member to JSON: " << e.what());
792+
return RETCODE_BAD_PARAMETER;
793+
}
763794
#endif // defined(MINGW_COMPILER)
764795
json_insert(member_name, utf8_value, output);
765796
}
@@ -790,17 +821,38 @@ ReturnCode_t json_serialize_basic_member(
790821
if (RETCODE_OK == ret)
791822
{
792823
// Insert UTF-8 converted value
793-
#ifdef MINGW_COMPILER
794824
std::string utf8_value;
795-
int size_needed = std::wcstombs(nullptr, value.data(), 0);
796-
if (size_needed > 0)
825+
#ifdef MINGW_COMPILER
826+
// WARNING: it is the user responsibility to set the appropiate UTF-8 locale before calling this method
827+
int size_needed = std::wcstombs(nullptr, value.c_str(), 0);
828+
if (size_needed < 0)
829+
{
830+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
831+
"Error encountered while serializing TK_STRING16 member to JSON: encountered invalid character.");
832+
return RETCODE_BAD_PARAMETER;
833+
}
834+
else if (size_needed > 0)
797835
{
798836
utf8_value.resize(size_needed);
799-
std::wcstombs(&utf8_value[0], value.data(), size_needed);
837+
if (std::wcstombs(&utf8_value[0], value.c_str(), size_needed) == static_cast<std::size_t>(-1))
838+
{
839+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
840+
"Error encountered while serializing TK_STRING16 member to JSON: encountered invalid character.");
841+
return RETCODE_BAD_PARAMETER;
842+
}
800843
}
801844
#else
802845
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
803-
std::string utf8_value = converter.to_bytes(value); // TODO: handle exception
846+
try
847+
{
848+
utf8_value = converter.to_bytes(value);
849+
}
850+
catch (const std::exception& e)
851+
{
852+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
853+
"Error encountered while serializing TK_STRING16 member to JSON: " << e.what());
854+
return RETCODE_BAD_PARAMETER;
855+
}
804856
#endif // defined(MINGW_COMPILER)
805857
json_insert(member_name, utf8_value, output);
806858
}
@@ -812,24 +864,17 @@ ReturnCode_t json_serialize_basic_member(
812864
}
813865
case TK_ENUM:
814866
{
815-
int32_t value;
816-
ReturnCode_t ret = data->get_int32_value(value, member_id);
817-
if (RETCODE_OK != ret)
818-
{
819-
EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_ENUM member to JSON.");
820-
return ret;
821-
}
822-
823-
// Get enumeration type to obtain the names of the different values
867+
// Get enumeration type to obtain the names of the different values, and also the underlying primitive type
824868
// NOTE: a different approach is required for collections and other "holder" types (e.g. structures),
825869
// as unlike with DynamicData::loan_value or DynamicData::get_X_value, DynamicData::get_descriptor method
826870
// is not meant to work with sequences nor arrays according to XTypes standard.
827-
traits<DynamicType>::ref_type enum_type;
871+
traits<DynamicTypeImpl>::ref_type enum_type;
828872
TypeKind holder_kind = data->enclosing_type()->get_kind();
873+
ReturnCode_t ret = RETCODE_OK;
829874
if (TK_ARRAY == holder_kind || TK_SEQUENCE == holder_kind)
830875
{
831876
const TypeDescriptorImpl& collection_descriptor = data->enclosing_type()->get_descriptor();
832-
enum_type = collection_descriptor.element_type();
877+
enum_type = traits<DynamicType>::narrow<DynamicTypeImpl>(collection_descriptor.element_type())->resolve_alias_enclosed_type();
833878
}
834879
else
835880
{
@@ -840,14 +885,67 @@ ReturnCode_t json_serialize_basic_member(
840885
"Error encountered while serializing TK_ENUM member to JSON: get_descriptor failed.");
841886
return ret;
842887
}
843-
enum_type = enum_desc->type();
888+
enum_type = traits<DynamicType>::narrow<DynamicTypeImpl>(enum_desc->type())->resolve_alias_enclosed_type();
889+
}
890+
891+
// Get value depending on the enclosing type
892+
assert(enum_type->get_kind() == TK_ENUM);
893+
TypeKind enclosing_kind = traits<DynamicType>::narrow<DynamicTypeImpl>(enum_type->get_all_members_by_index().at(0)->get_descriptor().type())->get_kind(); // Unfortunately DynamicDataImpl::get_enclosing_typekind is private
894+
nlohmann::json j_value;
895+
if (TK_INT8 == enclosing_kind)
896+
{
897+
int8_t value;
898+
ret = data->get_int8_value(value, member_id);
899+
j_value = value;
900+
}
901+
else if (TK_UINT8 == enclosing_kind)
902+
{
903+
uint8_t value;
904+
ret = data->get_uint8_value(value, member_id);
905+
j_value = value;
906+
}
907+
else if (TK_INT16 == enclosing_kind)
908+
{
909+
int16_t value;
910+
ret = data->get_int16_value(value, member_id);
911+
j_value = value;
912+
}
913+
else if (TK_UINT16 == enclosing_kind)
914+
{
915+
uint16_t value;
916+
ret = data->get_uint16_value(value, member_id);
917+
j_value = value;
918+
}
919+
else if (TK_INT32 == enclosing_kind)
920+
{
921+
int32_t value;
922+
ret = data->get_int32_value(value, member_id);
923+
j_value = value;
924+
}
925+
else if (TK_UINT32 == enclosing_kind)
926+
{
927+
uint32_t value;
928+
ret = data->get_uint32_value(value, member_id);
929+
j_value = value;
930+
}
931+
else
932+
{
933+
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
934+
"Error encountered while serializing TK_ENUM member to JSON: unexpected enclosing kind " <<
935+
enclosing_kind << " found.");
936+
return RETCODE_BAD_PARAMETER;
937+
}
938+
939+
if (RETCODE_OK != ret)
940+
{
941+
EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing TK_ENUM member to JSON.");
942+
return ret;
844943
}
845944

846945
DynamicTypeMembersByName all_members;
847946
if (RETCODE_OK !=
848947
(ret =
849-
traits<DynamicType>::narrow<DynamicTypeImpl>(enum_type)->resolve_alias_enclosed_type()->
850-
get_all_members_by_name(all_members)))
948+
enum_type->get_all_members_by_name(all_members)))
851949
{
852950
EPROSIMA_LOG_ERROR(XTYPES_UTILS,
853951
"Error encountered while serializing TK_ENUM member to JSON: get_all_members_by_name failed.");
@@ -860,7 +958,7 @@ ReturnCode_t json_serialize_basic_member(
860958
{
861959
MemberDescriptorImpl& enum_member_desc = traits<DynamicTypeMember>::narrow<DynamicTypeMemberImpl>(
862960
it.second)->get_descriptor();
863-
if (enum_member_desc.default_value() == std::to_string(value))
961+
if (enum_member_desc.default_value() == j_value.dump())
864962
{
865963
name = it.first;
866964
assert(name == it.second->get_name());
@@ -876,7 +974,7 @@ ReturnCode_t json_serialize_basic_member(
876974
}
877975
else if (format == DynamicDataJsonFormat::EPROSIMA)
878976
{
879-
nlohmann::json enum_dict = {{"name", name}, {"value", value}};
977+
nlohmann::json enum_dict = {{"name", name}, {"value", j_value}};
880978
json_insert(member_name, enum_dict, output);
881979
}
882980
}
@@ -902,20 +1000,18 @@ ReturnCode_t json_serialize_collection(
9021000
DynamicDataJsonFormat format) noexcept
9031001
{
9041002
ReturnCode_t ret = RETCODE_OK;
1003+
const TypeDescriptorImpl& descriptor = data->enclosing_type()->get_descriptor();
1004+
auto element_kind = traits<DynamicType>::narrow<DynamicTypeImpl>(descriptor.element_type())->resolve_alias_enclosed_type()->get_kind();
9051005
if (data->enclosing_type()->get_kind() == TK_SEQUENCE)
9061006
{
907-
const TypeDescriptorImpl& descriptor = data->enclosing_type()->get_descriptor();
908-
1007+
assert(descriptor.bound().size() == 1);
9091008
auto count = data->get_item_count();
9101009
nlohmann::json j_array = nlohmann::json::array();
9111010
for (uint32_t index = 0; index < count; ++index)
9121011
{
9131012
if (RETCODE_OK !=
9141013
(ret =
915-
json_serialize_member(data, static_cast<MemberId>(index),
916-
traits<DynamicType>::narrow<DynamicTypeImpl>(descriptor.element_type())->resolve_alias_enclosed_type()
917-
->get_kind(), j_array,
918-
format)))
1014+
json_serialize_member(data, static_cast<MemberId>(index), element_kind, j_array, format)))
9191015
{
9201016
EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing sequence collection to JSON.");
9211017
break;
@@ -928,13 +1024,10 @@ ReturnCode_t json_serialize_collection(
9281024
}
9291025
else
9301026
{
931-
const TypeDescriptorImpl& descriptor = data->enclosing_type()->get_descriptor();
932-
9331027
const BoundSeq& bounds = descriptor.bound();
9341028
nlohmann::json j_array = nlohmann::json::array();
9351029
unsigned int index = 0;
936-
if (RETCODE_OK != (ret = json_serialize_array(data, traits<DynamicType>::narrow<DynamicTypeImpl>(
937-
descriptor.element_type())->resolve_alias_enclosed_type()->get_kind(), index, bounds, j_array,
1030+
if (RETCODE_OK != (ret = json_serialize_array(data, element_kind, index, bounds, j_array,
9381031
format)))
9391032
{
9401033
EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing array collection to JSON.");
@@ -949,7 +1042,7 @@ ReturnCode_t json_serialize_collection(
9491042

9501043
ReturnCode_t json_serialize_array(
9511044
const traits<DynamicDataImpl>::ref_type& data,
952-
TypeKind member_kind,
1045+
TypeKind element_kind,
9531046
unsigned int& index,
9541047
const std::vector<unsigned int>& bounds,
9551048
nlohmann::json& j_array,
@@ -963,7 +1056,7 @@ ReturnCode_t json_serialize_array(
9631056
{
9641057
if (RETCODE_OK !=
9651058
(ret =
966-
json_serialize_member(data, static_cast<MemberId>(index++), member_kind, j_array,
1059+
json_serialize_member(data, static_cast<MemberId>(index++), element_kind, j_array,
9671060
format)))
9681061
{
9691062
EPROSIMA_LOG_ERROR(XTYPES_UTILS, "Error encountered while serializing array element to JSON.");
@@ -978,7 +1071,7 @@ ReturnCode_t json_serialize_array(
9781071
nlohmann::json inner_array = nlohmann::json::array();
9791072
if (RETCODE_OK !=
9801073
(ret =
981-
json_serialize_array(data, member_kind, index,
1074+
json_serialize_array(data, element_kind, index,
9821075
std::vector<unsigned int>(bounds.begin() + 1, bounds.end()), inner_array, format)))
9831076
{
9841077
EPROSIMA_LOG_ERROR(XTYPES_UTILS,

src/cpp/fastdds/xtypes/serializers/json/dynamic_data_json.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ ReturnCode_t json_serialize_collection(
7979

8080
ReturnCode_t json_serialize_array(
8181
const traits<DynamicDataImpl>::ref_type& data,
82-
TypeKind member_kind,
82+
TypeKind element_kind,
8383
unsigned int& index,
8484
const std::vector<unsigned int>& bounds,
8585
nlohmann::json& j_array,

0 commit comments

Comments
 (0)