Skip to content

Implement algorithm::hex_lower (Trac ticket #7064) #14

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

Merged
merged 3 commits into from
Mar 7, 2016
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
119 changes: 91 additions & 28 deletions include/boost/algorithm/hex.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
/*
Copyright (c) Marshall Clow 2011-2012.

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)

Thanks to Nevin for his comments/help.
*/

Expand All @@ -13,7 +13,7 @@
*/

/// \file hex.hpp
/// \brief Convert sequence of integral types into a sequence of hexadecimal
/// \brief Convert sequence of integral types into a sequence of hexadecimal
/// characters and back. Based on the MySQL functions HEX and UNHEX
/// \author Marshall Clow

Expand All @@ -33,17 +33,17 @@

namespace boost { namespace algorithm {

/*!
\struct hex_decode_error
\brief Base exception class for all hex decoding errors
/*!
\struct hex_decode_error
\brief Base exception class for all hex decoding errors
*/ /*!
\struct non_hex_input
\struct non_hex_input
\brief Thrown when a non-hex value (0-9, A-F) encountered when decoding.
Contains the offending character
*/ /*!
\struct not_enough_input
*/ /*!
\struct not_enough_input
\brief Thrown when the input sequence unexpectedly ends

*/
struct hex_decode_error : virtual boost::exception, virtual std::exception {};
struct not_enough_input : virtual hex_decode_error {};
Expand All @@ -54,12 +54,12 @@ namespace detail {
/// \cond DOXYGEN_HIDE

template <typename T, typename OutputIterator>
OutputIterator encode_one ( T val, OutputIterator out ) {
OutputIterator encode_one ( T val, OutputIterator out, const char * hexDigits ) {
const std::size_t num_hex_digits = 2 * sizeof ( T );
char res [ num_hex_digits ];
char *p = res + num_hex_digits;
for ( std::size_t i = 0; i < num_hex_digits; ++i, val >>= 4 )
*--p = "0123456789ABCDEF" [ val & 0x0F ];
*--p = hexDigits [ val & 0x0F ];
return std::copy ( res, res + num_hex_digits, out );
}

Expand Down Expand Up @@ -106,12 +106,12 @@ namespace detail {
typedef T value_type;
};

template <typename Iterator>
template <typename Iterator>
bool iter_end ( Iterator current, Iterator last ) { return current == last; }

template <typename T>
bool ptr_end ( const T* ptr, const T* /*end*/ ) { return *ptr == '\0'; }

// What can we assume here about the inputs?
// is std::iterator_traits<InputIterator>::value_type always 'char' ?
// Could it be wchar_t, say? Does it matter?
Expand All @@ -124,11 +124,11 @@ namespace detail {

// Need to make sure that we get can read that many chars here.
for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) {
if ( pred ( first, last ))
if ( pred ( first, last ))
BOOST_THROW_EXCEPTION (not_enough_input ());
res = ( 16 * res ) + hex_char_to_int (*first);
}

*out = res;
return ++out;
}
Expand All @@ -138,7 +138,7 @@ namespace detail {

/// \fn hex ( InputIterator first, InputIterator last, OutputIterator out )
/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters.
///
///
/// \param first The start of the input sequence
/// \param last One past the end of the input sequence
/// \param out An output iterator to the results into
Expand All @@ -148,14 +148,31 @@ template <typename InputIterator, typename OutputIterator>
typename boost::enable_if<boost::is_integral<typename detail::hex_iterator_traits<InputIterator>::value_type>, OutputIterator>::type
hex ( InputIterator first, InputIterator last, OutputIterator out ) {
for ( ; first != last; ++first )
out = detail::encode_one ( *first, out );
out = detail::encode_one ( *first, out, "0123456789ABCDEF" );
return out;
}


/// \fn hex_lower ( InputIterator first, InputIterator last, OutputIterator out )
/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters.
///
/// \param first The start of the input sequence
/// \param last One past the end of the input sequence
/// \param out An output iterator to the results into
/// \return The updated output iterator
/// \note Based on the MySQL function of the same name
template <typename InputIterator, typename OutputIterator>
typename boost::enable_if<boost::is_integral<typename detail::hex_iterator_traits<InputIterator>::value_type>, OutputIterator>::type
hex_lower ( InputIterator first, InputIterator last, OutputIterator out ) {
for ( ; first != last; ++first )
out = detail::encode_one ( *first, out, "0123456789abcdef" );
return out;
}


/// \fn hex ( const T *ptr, OutputIterator out )
/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters.
///
///
/// \param ptr A pointer to a 0-terminated sequence of data.
/// \param out An output iterator to the results into
/// \return The updated output iterator
Expand All @@ -164,13 +181,30 @@ template <typename T, typename OutputIterator>
typename boost::enable_if<boost::is_integral<T>, OutputIterator>::type
hex ( const T *ptr, OutputIterator out ) {
while ( *ptr )
out = detail::encode_one ( *ptr++, out );
out = detail::encode_one ( *ptr++, out, "0123456789ABCDEF" );
return out;
}


/// \fn hex_lower ( const T *ptr, OutputIterator out )
/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters.
///
/// \param ptr A pointer to a 0-terminated sequence of data.
/// \param out An output iterator to the results into
/// \return The updated output iterator
/// \note Based on the MySQL function of the same name
template <typename T, typename OutputIterator>
typename boost::enable_if<boost::is_integral<T>, OutputIterator>::type
hex_lower ( const T *ptr, OutputIterator out ) {
while ( *ptr )
out = detail::encode_one ( *ptr++, out, "0123456789abcdef" );
return out;
}


/// \fn hex ( const Range &r, OutputIterator out )
/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters.
///
///
/// \param r The input range
/// \param out An output iterator to the results into
/// \return The updated output iterator
Expand All @@ -182,9 +216,23 @@ hex ( const Range &r, OutputIterator out ) {
}


/// \fn hex_lower ( const Range &r, OutputIterator out )
/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters.
///
/// \param r The input range
/// \param out An output iterator to the results into
/// \return The updated output iterator
/// \note Based on the MySQL function of the same name
template <typename Range, typename OutputIterator>
typename boost::enable_if<boost::is_integral<typename detail::hex_iterator_traits<typename Range::iterator>::value_type>, OutputIterator>::type
hex_lower ( const Range &r, OutputIterator out ) {
return hex_lower (boost::begin(r), boost::end(r), out);
}


/// \fn unhex ( InputIterator first, InputIterator last, OutputIterator out )
/// \brief Converts a sequence of hexadecimal characters into a sequence of integers.
///
///
/// \param first The start of the input sequence
/// \param last One past the end of the input sequence
/// \param out An output iterator to the results into
Expand All @@ -200,7 +248,7 @@ OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator o

/// \fn unhex ( const T *ptr, OutputIterator out )
/// \brief Converts a sequence of hexadecimal characters into a sequence of integers.
///
///
/// \param ptr A pointer to a null-terminated input sequence.
/// \param out An output iterator to the results into
/// \return The updated output iterator
Expand All @@ -218,7 +266,7 @@ OutputIterator unhex ( const T *ptr, OutputIterator out ) {

/// \fn OutputIterator unhex ( const Range &r, OutputIterator out )
/// \brief Converts a sequence of hexadecimal characters into a sequence of integers.
///
///
/// \param r The input range
/// \param out An output iterator to the results into
/// \return The updated output iterator
Expand All @@ -231,7 +279,7 @@ OutputIterator unhex ( const Range &r, OutputIterator out ) {

/// \fn String hex ( const String &input )
/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters.
///
///
/// \param input A container to be converted
/// \return A container with the encoded text
template<typename String>
Expand All @@ -242,9 +290,24 @@ String hex ( const String &input ) {
return output;
}


/// \fn String hex_lower ( const String &input )
/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters.
///
/// \param input A container to be converted
/// \return A container with the encoded text
template<typename String>
String hex_lower ( const String &input ) {
String output;
output.reserve (input.size () * (2 * sizeof (typename String::value_type)));
(void) hex_lower (input, std::back_inserter (output));
return output;
}


/// \fn String unhex ( const String &input )
/// \brief Converts a sequence of hexadecimal characters into a sequence of characters.
///
///
/// \param input A container to be converted
/// \return A container with the decoded text
template<typename String>
Expand Down
39 changes: 39 additions & 0 deletions test/hex_test1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <boost/config.hpp>
#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string/case_conv.hpp>

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
Expand Down Expand Up @@ -42,6 +43,31 @@ void test_to_hex ( const typename String::value_type ** tests ) {
}
}

template<typename String>
void test_to_hex_lower ( const typename String::value_type ** tests ) {
for ( const typename String::value_type **p = tests; *p; p++ ) {
String arg, argh, one, two, three, four;
arg.assign ( *p );
boost::algorithm::hex_lower ( *p, std::back_inserter ( one ));
boost::algorithm::hex_lower ( arg, std::back_inserter ( two ));
boost::algorithm::hex_lower ( arg.begin (), arg.end (), std::back_inserter ( three ));
four = boost::algorithm::hex_lower ( arg );
BOOST_CHECK ( one == two );
BOOST_CHECK ( one == three );
BOOST_CHECK ( one == four );
argh = one;
one.clear (); two.clear (); three.clear (); four.clear ();
boost::algorithm::unhex ( argh.c_str (), std::back_inserter ( one ));
boost::algorithm::unhex ( argh, std::back_inserter ( two ));
boost::algorithm::unhex ( argh.begin (), argh.end (), std::back_inserter ( three ));
four = boost::algorithm::unhex ( argh );
BOOST_CHECK ( one == two );
BOOST_CHECK ( one == three );
BOOST_CHECK ( one == four );
BOOST_CHECK ( one == arg );
}
}


template<typename String>
void test_from_hex_success ( const typename String::value_type ** tests ) {
Expand All @@ -61,6 +87,11 @@ void test_from_hex_success ( const typename String::value_type ** tests ) {
boost::algorithm::hex ( argh, std::back_inserter ( two ));
boost::algorithm::hex ( argh.begin (), argh.end (), std::back_inserter ( three ));
four = boost::algorithm::hex ( argh );
boost::algorithm::to_lower( arg );
boost::algorithm::to_lower( one );
boost::algorithm::to_lower( two );
boost::algorithm::to_lower( three );
boost::algorithm::to_lower( four );
BOOST_CHECK ( one == two );
BOOST_CHECK ( one == three );
BOOST_CHECK ( one == four );
Expand Down Expand Up @@ -113,13 +144,15 @@ const wchar_t *tohex_w [] = {
const char *fromhex [] = {
"20",
"2122234556FF",
"2122234556ff",
NULL // End of the list
};


const wchar_t *fromhex_w [] = {
L"00101020",
L"2122234556FF3456",
L"2122234556ff3456",
NULL // End of the list
};

Expand All @@ -129,6 +162,8 @@ const char *fromhex_fail [] = {
"H",
"234",
"21222G4556FF",
"h",
"21222g4556ff",
NULL // End of the list
};

Expand All @@ -139,17 +174,21 @@ const wchar_t *fromhex_fail_w [] = {
L"H",
L"234",
L"21222G4556FF",
L"h",
L"21222g4556ff",
NULL // End of the list
};


BOOST_AUTO_TEST_CASE( test_main )
{
test_to_hex<std::string> ( tohex );
test_to_hex_lower<std::string> ( tohex );
test_from_hex_success<std::string> ( fromhex );
test_from_hex_failure<std::string> ( fromhex_fail );

test_to_hex<std::wstring> ( tohex_w );
test_to_hex_lower<std::wstring> ( tohex_w );
test_from_hex_success<std::wstring> ( fromhex_w );
test_from_hex_failure<std::wstring> ( fromhex_fail_w );
}