Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions include/fastcdr/Cdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2727,6 +2727,52 @@ class Cdr
MemberId member_id;
xcdr1_deserialize_member_header(member_id, current_state);
auto prev_offset = offset_;
member_value.reset(0 < current_state.member_size_);
if (0 < current_state.member_size_)
{
deserialize(member_value);
}
size_t member_size {current_state.member_size_};
size_t diff {offset_ - prev_offset};
if (member_size < diff)
{
throw exception::BadParamException(
"Member size provided by member header is lower than real decoded member size");
}

// Skip unused bytes
offset_ += (member_size - diff);
}
else
{
deserialize(member_value);
}
return *this;
}

/*!
* @brief Decodes an optional member of an external according to the encoding algorithm used.
* @param[out] member_value A reference of the variable where the optional member value will be stored.
* @return Reference to the eprosima::fastcdr::Cdr object.
* @exception exception::NotEnoughMemoryException This exception is thrown when trying to decode from a buffer
* position that exceeds the internal memory size.
*/
template<class _T>
Cdr& deserialize_member(
optional<external<_T>>& member_value)
{
if (member_value.has_value() && member_value.value().is_locked())
{
throw exception::BadParamException("External member is locked");
}

if (EncodingAlgorithmFlag::PLAIN_CDR == current_encoding_)
{
Cdr::state current_state(*this);
MemberId member_id;
xcdr1_deserialize_member_header(member_id, current_state);
auto prev_offset = offset_;
member_value.reset(0 < current_state.member_size_);
if (0 < current_state.member_size_)
{
deserialize(member_value);
Expand Down
146 changes: 145 additions & 1 deletion test/xcdr/external.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ using XCdrStreamValues =
1 + EncodingAlgorithmFlag::PL_CDR2 + Cdr::Endianness::LITTLE_ENDIANNESS>;


class XCdrExternalTest : public ::testing::TestWithParam< std::tuple<EncodingAlgorithmFlag, Cdr::Endianness>>
class XCdrExternalTest : public ::testing::TestWithParam<std::tuple<EncodingAlgorithmFlag, Cdr::Endianness>>
{
};

Expand Down Expand Up @@ -1158,6 +1158,150 @@ TEST_P(XCdrExternalTest, null_optional)

}

/*!
* @test Test encoding of an empty optional field of an external.
* @code{.idl}
* struct ExternalClass
* {
* string var_str;
* };
*
* struct NullOptional
* {
* @optional @external
* ExternalClass var_ext;
* };
* @endcode
*/
TEST(XCdrExternalTest, null_optional_on_initiated_value)
{
//{ Defining expected XCDR streams
XCdrStreamValues expected_streams;
expected_streams[0 + EncodingAlgorithmFlag::PLAIN_CDR + Cdr::Endianness::BIG_ENDIANNESS] =
{
0x00, 0x00, 0x00, 0x00, // Encapsulation
0x00, 0x01, 0x00, 0x00 // ShortMemberHeader
};
expected_streams[0 + EncodingAlgorithmFlag::PLAIN_CDR + Cdr::Endianness::LITTLE_ENDIANNESS] =
{
0x00, 0x01, 0x00, 0x00, // Encapsulation
0x01, 0x00, 0x00, 0x00 // ShortMemberHeader
};
//}

optional<external<ExternalClass>> opt_value;

for (uint8_t tested_stream {0}; tested_stream < 2; ++tested_stream)
{

//{ Calculate encoded size.
CdrSizeCalculator calculator(get_version_from_algorithm(EncodingAlgorithmFlag::PLAIN_CDR));
size_t current_alignment {0};
size_t calculated_size {calculator.begin_calculate_type_serialized_size(EncodingAlgorithmFlag::PLAIN_CDR,
current_alignment)};
calculated_size += calculator.calculate_member_serialized_size(MemberId(1), opt_value, current_alignment);
calculated_size += calculator.end_calculate_type_serialized_size(EncodingAlgorithmFlag::PLAIN_CDR,
current_alignment);
calculated_size += 4; // Encapsulation
//}


{

//{ Prepare buffer
auto buffer =
std::unique_ptr<char, void (*)(
void*)>{reinterpret_cast<char*>(calloc(expected_streams[tested_stream].size(), sizeof(char))), free};
FastBuffer fast_buffer(buffer.get(), expected_streams[tested_stream].size());
Cdr cdr(fast_buffer,
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS,
get_version_from_algorithm(EncodingAlgorithmFlag::PLAIN_CDR));
//}

//{ Encode optional not present.
cdr.set_encoding_flag(EncodingAlgorithmFlag::PLAIN_CDR);
cdr.serialize_encapsulation();
Cdr::state enc_state(cdr);
cdr.begin_serialize_type(enc_state, EncodingAlgorithmFlag::PLAIN_CDR);
cdr.serialize_member(MemberId(1), opt_value);
cdr.end_serialize_type(enc_state);
cdr.set_dds_cdr_options({0, 0});
Cdr::state enc_state_end(cdr);
//}

//{ Test encoded content
ASSERT_EQ(cdr.get_serialized_data_length(), expected_streams[tested_stream].size());
ASSERT_EQ(cdr.get_serialized_data_length(), calculated_size);
ASSERT_EQ(0, memcmp(buffer.get(), expected_streams[tested_stream].data(),
expected_streams[tested_stream].size()));
//}

//{ Decoding optional not present
optional<external<ExternalClass>> dopt_value {{new ExternalClass("CD")}};
cdr.reset();
cdr.read_encapsulation();
ASSERT_EQ(cdr.get_encoding_flag(), EncodingAlgorithmFlag::PLAIN_CDR);
ASSERT_EQ(cdr.endianness(),
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS);
cdr.deserialize_type(EncodingAlgorithmFlag::PLAIN_CDR, [&](Cdr& cdr_inner, const MemberId&)->bool
{
cdr_inner.deserialize_member(dopt_value);

return false;
});
ASSERT_FALSE(dopt_value.has_value());
//}
}

{
//{ Prepare buffer
auto buffer =
std::unique_ptr<char, void (*)(
void*)>{reinterpret_cast<char*>(calloc(expected_streams[tested_stream].size(), sizeof(char))), free};
FastBuffer fast_buffer(buffer.get(), expected_streams[tested_stream].size());
Cdr cdr(fast_buffer,
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS,
get_version_from_algorithm(EncodingAlgorithmFlag::PLAIN_CDR));
//}

//{ Encode optional not present.
cdr.set_encoding_flag(EncodingAlgorithmFlag::PLAIN_CDR);
cdr.serialize_encapsulation();
Cdr::state enc_state(cdr);
cdr.begin_serialize_type(enc_state, EncodingAlgorithmFlag::PLAIN_CDR);
cdr << MemberId(1) << opt_value;
cdr.end_serialize_type(enc_state);
cdr.set_dds_cdr_options({0, 0});
Cdr::state enc_state_end(cdr);
//}

//{ Test encoded content
ASSERT_EQ(cdr.get_serialized_data_length(), expected_streams[tested_stream].size());
ASSERT_EQ(cdr.get_serialized_data_length(), calculated_size);
ASSERT_EQ(0, memcmp(buffer.get(), expected_streams[tested_stream].data(),
expected_streams[tested_stream].size()));
//}

//{ Decoding optional not present
optional<external<ExternalClass>> dopt_value{{ new ExternalClass("CD") }};
cdr.reset();
cdr.read_encapsulation();
ASSERT_EQ(cdr.get_encoding_flag(), EncodingAlgorithmFlag::PLAIN_CDR);
ASSERT_EQ(cdr.endianness(),
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS);
cdr.deserialize_type(EncodingAlgorithmFlag::PLAIN_CDR, [&](Cdr& cdr_inner, const MemberId&)->bool
{
cdr_inner >> dopt_value;

return false;
});
ASSERT_FALSE(dopt_value.has_value());
//}
}
}

}

/*!
* @test Test encoding of an optional with an empty external field of ExternalClass type
* @code{.idl}
Expand Down
139 changes: 138 additions & 1 deletion test/xcdr/optional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ using XCdrStreamValues =
1 + EncodingAlgorithmFlag::PL_CDR2 + Cdr::Endianness::LITTLE_ENDIANNESS>;


class XCdrOptionalTest : public ::testing::TestWithParam< std::tuple<EncodingAlgorithmFlag, Cdr::Endianness>>
class XCdrOptionalTest : public ::testing::TestWithParam<std::tuple<EncodingAlgorithmFlag, Cdr::Endianness>>
{
};

Expand Down Expand Up @@ -7913,6 +7913,143 @@ TEST_P(XCdrOptionalTest, two_inner_short_optional)
}
}

/*!
* @test Test encoding of an empty optional field of octet type
* @code{.idl}
* struct NullOptional
* {
* @optional
* octet var_octet;
* };
* @endcode
*/
TEST(XCdrOptionalTest, plaincdr_regression_test)
{
//{ Defining expected XCDR streams
XCdrStreamValues expected_streams;
expected_streams[0 + EncodingAlgorithmFlag::PLAIN_CDR + Cdr::Endianness::BIG_ENDIANNESS] =
{
0x00, 0x00, 0x00, 0x00, // Encapsulation
0x00, 0x01, 0x00, 0x00 // ShortMemberHeader
};
expected_streams[0 + EncodingAlgorithmFlag::PLAIN_CDR + Cdr::Endianness::LITTLE_ENDIANNESS] =
{
0x00, 0x01, 0x00, 0x00, // Encapsulation
0x01, 0x00, 0x00, 0x00 // ShortMemberHeader
};
//}

optional<uint8_t> opt_value;

for (uint8_t tested_stream {0}; tested_stream < 2; ++tested_stream)
{

//{ Calculate encoded size.
CdrSizeCalculator calculator(get_version_from_algorithm(EncodingAlgorithmFlag::PLAIN_CDR));
size_t current_alignment {0};
size_t calculated_size {calculator.begin_calculate_type_serialized_size(EncodingAlgorithmFlag::PLAIN_CDR,
current_alignment)};
calculated_size += calculator.calculate_member_serialized_size(MemberId(1), opt_value, current_alignment);
calculated_size += calculator.end_calculate_type_serialized_size(EncodingAlgorithmFlag::PLAIN_CDR,
current_alignment);
calculated_size += 4; // Encapsulation
//}

{

//{ Prepare buffer
auto buffer =
std::unique_ptr<char, void (*)(
void*)>{reinterpret_cast<char*>(calloc(expected_streams[tested_stream].size(), sizeof(char))), free};
FastBuffer fast_buffer(buffer.get(), expected_streams[tested_stream].size());
Cdr cdr(fast_buffer,
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS,
get_version_from_algorithm(EncodingAlgorithmFlag::PLAIN_CDR));
//}

//{ Encode optional not present.
cdr.set_encoding_flag(EncodingAlgorithmFlag::PLAIN_CDR);
cdr.serialize_encapsulation();
Cdr::state enc_state(cdr);
cdr.begin_serialize_type(enc_state, EncodingAlgorithmFlag::PLAIN_CDR);
cdr.serialize_member(MemberId(1), opt_value);
cdr.end_serialize_type(enc_state);
cdr.set_dds_cdr_options({0, 0});
Cdr::state enc_state_end(cdr);
//}

//{ Test encoded content
ASSERT_EQ(cdr.get_serialized_data_length(), expected_streams[tested_stream].size());
ASSERT_EQ(cdr.get_serialized_data_length(), calculated_size);
ASSERT_EQ(0, memcmp(buffer.get(), expected_streams[tested_stream].data(),
expected_streams[tested_stream].size()));
//}

//{ Decoding optional not present
optional<uint8_t> dopt_value {3};
cdr.reset();
cdr.read_encapsulation();
ASSERT_EQ(cdr.get_encoding_flag(), EncodingAlgorithmFlag::PLAIN_CDR);
ASSERT_EQ(cdr.endianness(),
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS);
cdr.deserialize_type(EncodingAlgorithmFlag::PLAIN_CDR, [&](Cdr& cdr_inner, const MemberId&)->bool
{
cdr_inner.deserialize_member(dopt_value);

return false;
});
ASSERT_FALSE(dopt_value.has_value());
//}
}

{
//{ Prepare buffer
auto buffer =
std::unique_ptr<char, void (*)(
void*)>{reinterpret_cast<char*>(calloc(expected_streams[tested_stream].size(), sizeof(char))), free};
FastBuffer fast_buffer(buffer.get(), expected_streams[tested_stream].size());
Cdr cdr(fast_buffer,
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS,
get_version_from_algorithm(EncodingAlgorithmFlag::PLAIN_CDR));
//}

//{ Encode optional not present.
cdr.set_encoding_flag(EncodingAlgorithmFlag::PLAIN_CDR);
cdr.serialize_encapsulation();
Cdr::state enc_state(cdr);
cdr.begin_serialize_type(enc_state, EncodingAlgorithmFlag::PLAIN_CDR);
cdr << MemberId(1) << opt_value;
cdr.end_serialize_type(enc_state);
cdr.set_dds_cdr_options({0, 0});
Cdr::state enc_state_end(cdr);
//}

//{ Test encoded content
ASSERT_EQ(cdr.get_serialized_data_length(), expected_streams[tested_stream].size());
ASSERT_EQ(cdr.get_serialized_data_length(), calculated_size);
ASSERT_EQ(0, memcmp(buffer.get(), expected_streams[tested_stream].data(),
expected_streams[tested_stream].size()));
//}

//{ Decoding optional not present
optional<uint8_t> dopt_value {3};
cdr.reset();
cdr.read_encapsulation();
ASSERT_EQ(cdr.get_encoding_flag(), EncodingAlgorithmFlag::PLAIN_CDR);
ASSERT_EQ(cdr.endianness(),
0 == tested_stream ? Cdr::Endianness::BIG_ENDIANNESS : Cdr::Endianness::LITTLE_ENDIANNESS);
cdr.deserialize_type(EncodingAlgorithmFlag::PLAIN_CDR, [&](Cdr& cdr_inner, const MemberId&)->bool
{
cdr_inner >> dopt_value;

return false;
});
ASSERT_FALSE(dopt_value.has_value());
//}
}
}
}

INSTANTIATE_TEST_SUITE_P(
XCdrTest,
XCdrOptionalTest,
Expand Down
Loading