Skip to content

Commit

Permalink
Fixes and additional tests for issue #120 (PR #121)
Browse files Browse the repository at this point in the history
  • Loading branch information
KimonHoffmann authored Nov 8, 2024
2 parents 678838b + d4a3b8f commit e6d97fd
Show file tree
Hide file tree
Showing 12 changed files with 306 additions and 33 deletions.
7 changes: 5 additions & 2 deletions libember/Headers/ember/ber/detail/MultiByte.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ namespace libember { namespace ber { namespace detail
util::OctetStream::value_type byte = 0;
do
{
byte = input.front();
if (input.empty())
{
throw std::runtime_error("Not enough data");
}
byte = input.front();
input.consume();
++byteCount;
result = (result << 7) | (byte & ~0x80);
Expand All @@ -110,4 +114,3 @@ namespace libember { namespace ber { namespace detail
}

#endif // __LIBEMBER_BER_DETAIL_MULTIBYTE_HPP

5 changes: 4 additions & 1 deletion libember/Headers/ember/ber/traits/Boolean.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ namespace libember { namespace ber

static value_type decode(util::OctetStream& input, std::size_t)
{
if (input.empty())
{
throw std::runtime_error("Not enough data");
}
util::OctetStream::value_type const byte = input.front();
input.consume();
return (byte != 0);
Expand All @@ -83,4 +87,3 @@ namespace libember { namespace ber
}

#endif // __LIBEMBER_BER_TRAITS_BOOLEAN_HPP

5 changes: 4 additions & 1 deletion libember/Headers/ember/ber/traits/Integral.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ namespace libember { namespace ber

static value_type decode(util::OctetStream& input, std::size_t encodedLength)
{
if (input.size() < encodedLength)
{
throw std::runtime_error("Not enough data");
}
typedef typename meta::MakeUnsigned<value_type>::type unsigned_type;
value_type value = 0;
for (std::size_t index = 0; index < encodedLength; ++index)
Expand Down Expand Up @@ -347,4 +351,3 @@ namespace libember { namespace ber
}

#endif // __LIBEMBER_BER_TRAITS_INTEGRAL_HPP

10 changes: 9 additions & 1 deletion libember/Headers/ember/ber/traits/Length.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ namespace libember { namespace ber

static Length<LengthType> decode(util::OctetStream& input)
{
if (input.empty())
{
throw std::runtime_error("Not enough data");
}

underlying_type length = input.front();
input.consume();

Expand All @@ -86,6 +91,10 @@ namespace libember { namespace ber
}
else
{
if (input.size() < bytes)
{
throw std::runtime_error("Not enough data");
}
length = 0U;
for (/* Nothing */; bytes > 0U; bytes -= 1U)
{
Expand All @@ -101,4 +110,3 @@ namespace libember { namespace ber
}

#endif // __LIBEMBER_BER_TRAITS_LENGTH_HPP

4 changes: 2 additions & 2 deletions libember/Headers/ember/ber/traits/ObjectIdentifier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace libember { namespace ber
std::size_t length = 0;
value_type::const_iterator first = value.begin();
value_type::const_iterator const last = value.end();

for (/* Nothing */; first != last; ++first)
{
length += detail::getMultiByteEncodedLength(*first);
Expand Down Expand Up @@ -82,6 +82,7 @@ namespace libember { namespace ber

static value_type decode(util::OctetStream& input, std::size_t size)
{
// Note: Multibyte decoding already verifies validity of the given size.
typedef ObjectIdentifier::value_type item_type;
std::vector<item_type> items;
while(size > 0)
Expand All @@ -98,4 +99,3 @@ namespace libember { namespace ber
}

#endif // __LIBEMBER_BER_TRAITS_OBJECTIDENTIFIER_HPP

47 changes: 35 additions & 12 deletions libember/Headers/ember/ber/traits/Real.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Integral.hpp"
#include "../../meta/FunctionTraits.hpp"
#include "../../util/TypePun.hpp"
#include "../../util/SignBit.hpp"

//SimianIgnore

Expand Down Expand Up @@ -62,15 +63,22 @@ namespace libember { namespace ber
// 0x42 Indicates NaN
output.append(0x42);
}
else if (
(value == static_cast<value_type>(0.0)) &&
util::signbit(value))
{
// 0x43 Indicates -0.0
output.append(0x43);
}
else
{
double const real = value;
unsigned long long const bits = util::type_pun<unsigned long long>(real);

if (bits != 0)
{
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
mantissa |= 0x0010000000000000ULL;

while((mantissa & 0xFF) == 0x00)
Expand Down Expand Up @@ -109,8 +117,8 @@ namespace libember { namespace ber

if (bits != 0)
{
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
long long const exponent = ((0x7FF0000000000000LL & bits) >> 52) - 1023;
unsigned long long mantissa = 0x000FFFFFFFFFFFFFULL & bits;
mantissa |= 0x0010000000000000ULL;

while((mantissa & 0xFF) == 0x00)
Expand Down Expand Up @@ -152,38 +160,54 @@ namespace libember { namespace ber
static value_type decode(util::OctetStream& input, std::size_t encodedLength)
{
if (encodedLength == 0)
{
return static_cast<value_type>(0.0);
}

if (encodedLength > input.size())
{
throw std::runtime_error("Not enough data");
}

unsigned char const preamble = input.front();
input.consume();

if (encodedLength == 1 && preamble == 0x40)
if ((encodedLength == 1) && (preamble == 0x40))
{
return +std::numeric_limits<value_type>::infinity();
}
else if (encodedLength == 1 && preamble == 0x41)
else if ((encodedLength == 1) && (preamble == 0x41))
{
return -std::numeric_limits<value_type>::infinity();
}
else if (encodedLength == 1 && preamble == 0x42)
else if ((encodedLength == 1) && (preamble == 0x42))
{
return std::numeric_limits<value_type>::quiet_NaN();
}
else if ((encodedLength == 1) && (preamble == 0x43))
{
return static_cast<value_type>(-0.0);
}
else
{
unsigned long long bits = 0;
unsigned int const sign = (preamble & 0x40);
unsigned int const exponentLength = 1 + (preamble & 3);
unsigned int const mantissaShift = ((preamble >> 2) & 3);

// Note: If (exponentLength > encodedLength - 1), the following call to decode will throw,
// so there is no need to check this separately.
long long exponent = ber::decode<long long>(input, exponentLength);
unsigned long long mantissa = ber::decode<unsigned long long>(input, encodedLength - exponentLength - 1) << mantissaShift;

while((mantissa & 0x7FFFF00000000000ULL) == 0x00)
mantissa <<= 8;
if (mantissa != 0)
{
while((mantissa & 0x7FFFF00000000000ULL) == 0x00)
mantissa <<= 8;

while((mantissa & 0x7FF0000000000000ULL) == 0x00)
mantissa <<= 1;
while((mantissa & 0x7FF0000000000000ULL) == 0x00)
mantissa <<= 1;
}

mantissa &= 0x0FFFFFFFFFFFFFULL;
bits = (static_cast<unsigned long long>(exponent + 1023) << 52) | mantissa;
Expand Down Expand Up @@ -246,4 +270,3 @@ namespace libember { namespace ber
//EndSimianIgnore

#endif // __LIBEMBER_BER_TRAITS_REAL_HPP

6 changes: 5 additions & 1 deletion libember/Headers/ember/ber/traits/Tag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ namespace libember { namespace ber

static value_type decode(util::OctetStream& input)
{
if (input.empty())
{
throw std::runtime_error("Not enough data");
}

util::OctetStream::value_type byte = input.front();
input.consume();

Expand All @@ -82,4 +87,3 @@ namespace libember { namespace ber
}

#endif // __LIBEMBER_BER_TRAITS_TAG_HPP

28 changes: 28 additions & 0 deletions libember/Headers/ember/util/SignBit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
libember -- C++ 03 implementation of the Ember+ Protocol
Copyright (C) 2024 Lawo AG (http://www.lawo.com).
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/

#ifndef __LIBEMBER_UTIL_SIGNBIT_HPP
#define __LIBEMBER_UTIL_SIGNBIT_HPP

#include "TypePun.hpp"

namespace libember { namespace util
{
inline bool signbit(float value)
{
return (type_pun<unsigned int>(value) & 0x80000000U) != 0U;
}

inline bool signbit(double value)
{
return (type_pun<unsigned long long>(value) & 0x8000000000000000LLU) != 0LLU;
}
}
}

#endif // __LIBEMBER_UTIL_SIGNBIT_HPP
32 changes: 32 additions & 0 deletions libember/Tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ target_link_libraries(libember-test-dynamic_encode_decode PRIVATE ember-headeron
enable_warnings_on_target(libember-test-dynamic_encode_decode)


add_executable(libember-test-decode_length_check ber/DecodeLengthCheck.cpp)
set_target_properties(libember-test-decode_length_check
PROPERTIES
POSITION_INDEPENDENT_CODE ON
VISIBILITY_INLINES_HIDDEN ON
C_VISIBILITY_PRESET hidden
CXX_VISIBILITY_PRESET hidden
C_EXTENSIONS OFF
CXX_EXTENSIONS OFF
)
target_link_libraries(libember-test-decode_length_check PRIVATE ember-headeronly)
enable_warnings_on_target(libember-test-decode_length_check)


add_executable(libember-test-glow_value glow/GlowValue.cpp)
set_target_properties(libember-test-glow_value
PROPERTIES
Expand All @@ -69,7 +83,25 @@ if (NOT CMAKE_BUILD_TYPE MATCHES "Debug")
set_target_properties(libember-test-streambuffer PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
set_target_properties(libember-test-static_encode_decode PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
set_target_properties(libember-test-dynamic_encode_decode PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
set_target_properties(libember-test-decode_length_check PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
set_target_properties(libember-test-glow_value PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
endif()
endif()


include(CTest)

add_test(NAME length-negative_zero COMMAND libember-test-decode_length_check negative_zero)
add_test(NAME length-encoded_length COMMAND libember-test-decode_length_check encoded_length)
add_test(NAME length-exponent_length COMMAND libember-test-decode_length_check exponent_length)
add_test(NAME length-zero_mantissa COMMAND libember-test-decode_length_check zero_mantissa)
add_test(NAME length-preamble_length_not_one COMMAND libember-test-decode_length_check preamble_length_not_one)
add_test(NAME length-integral COMMAND libember-test-decode_length_check integral)
add_test(NAME length-boolean COMMAND libember-test-decode_length_check boolean)
add_test(NAME length-length_first_byte COMMAND libember-test-decode_length_check length_first_byte)
add_test(NAME length-length_second_byte COMMAND libember-test-decode_length_check length_second_byte)
add_test(NAME length-object_identifier_empty COMMAND libember-test-decode_length_check object_identifier_empty)
add_test(NAME length-object_identifier_too_short COMMAND libember-test-decode_length_check object_identifier_too_short)
add_test(NAME length-tag COMMAND libember-test-decode_length_check tag)
add_test(NAME length-tag_multibyte COMMAND libember-test-decode_length_check tag_multibyte)
add_test(NAME length-tag_multibyte_too_short COMMAND libember-test-decode_length_check tag_multibyte_too_short)
Loading

0 comments on commit e6d97fd

Please sign in to comment.