Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes and additional tests for issue #120 #121

Merged
merged 4 commits into from
Nov 8, 2024
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
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
Loading