Skip to content
Open
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
50 changes: 48 additions & 2 deletions include/fastcdr/Cdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ class Cdr
* @exception exception::NotEnoughMemoryException This exception is thrown when trying to encode into a buffer
* position that exceeds the internal memory size.
*/
template <size_t MAX_CHARS>
template<size_t MAX_CHARS>
Cdr& serialize(
const fixed_string<MAX_CHARS>& value)
{
Expand Down Expand Up @@ -1787,7 +1787,7 @@ class Cdr
* @exception exception::NotEnoughMemoryException This exception is thrown when trying to decode from a buffer
* position that exceeds the internal memory size.
*/
template <size_t MAX_CHARS>
template<size_t MAX_CHARS>
Cdr& deserialize(
fixed_string<MAX_CHARS>& value)
{
Expand Down 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
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