fixed a bug in boost::algorithm::unhex(T*,) where it was throwing the wrong exception on short input

[SVN r79588]
This commit is contained in:
Marshall Clow
2012-07-18 18:16:39 +00:00
parent 26edcb7b51
commit 1fd1894ed7
2 changed files with 30 additions and 38 deletions

View File

@ -110,33 +110,25 @@ namespace detail {
typedef T value_type; typedef T value_type;
}; };
// Output Iterators have a value type of 'void'. Kinda sucks.
// We special case some output iterators, but we can't enumerate them all.
// If we can't figure it out, we assume that you want to output chars.
// If you don't, pass in an iterator with a real value_type.
template <typename T> struct value_type_or_char { typedef T value_type; };
template <> struct value_type_or_char<void> { typedef char value_type; };
// All in one step
template <typename Iterator> template <typename Iterator>
struct iterator_value_type { bool iter_end ( Iterator current, Iterator last ) { return current == last; }
// typedef typename value_type_or_char<typename hex_iterator_traits<Iterator>::value_type>::value_type value_type;
typedef typename hex_iterator_traits<Iterator>::value_type value_type; template <typename T>
}; bool ptr_end ( const T* ptr, const T* /*end*/ ) { return *ptr == '\0'; }
// What can we assume here about the inputs? // What can we assume here about the inputs?
// is std::iterator_traits<InputIterator>::value_type always 'char' ? // is std::iterator_traits<InputIterator>::value_type always 'char' ?
// Could it be wchar_t, say? Does it matter? // Could it be wchar_t, say? Does it matter?
// We are assuming ASCII for the values - but what about the storage? // We are assuming ASCII for the values - but what about the storage?
template <typename InputIterator, typename OutputIterator> template <typename InputIterator, typename OutputIterator, typename EndPred>
typename boost::enable_if<boost::is_integral<typename iterator_value_type<OutputIterator>::value_type>, OutputIterator>::type typename boost::enable_if<boost::is_integral<typename hex_iterator_traits<OutputIterator>::value_type>, OutputIterator>::type
decode_one ( InputIterator &first, InputIterator last, OutputIterator out ) { decode_one ( InputIterator &first, InputIterator last, OutputIterator out, EndPred pred ) {
typedef typename iterator_value_type<OutputIterator>::value_type T; typedef typename hex_iterator_traits<OutputIterator>::value_type T;
T res (0); T res (0);
// Need to make sure that we get can read that many chars here. // 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 ) { for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) {
if ( first == last ) if ( pred ( first, last ))
BOOST_THROW_EXCEPTION (not_enough_input ()); BOOST_THROW_EXCEPTION (not_enough_input ());
res = ( 16 * res ) + hex_char_to_int (static_cast<char> (*first)); res = ( 16 * res ) + hex_char_to_int (static_cast<char> (*first));
} }
@ -205,7 +197,7 @@ hex ( const Range &r, OutputIterator out ) {
template <typename InputIterator, typename OutputIterator> template <typename InputIterator, typename OutputIterator>
OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator out ) { OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator out ) {
while ( first != last ) while ( first != last )
out = detail::decode_one ( first, last, out ); out = detail::decode_one ( first, last, out, detail::iter_end<InputIterator> );
return out; return out;
} }
@ -219,12 +211,12 @@ OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator o
/// \note Based on the MySQL function of the same name /// \note Based on the MySQL function of the same name
template <typename T, typename OutputIterator> template <typename T, typename OutputIterator>
OutputIterator unhex ( const T *ptr, OutputIterator out ) { OutputIterator unhex ( const T *ptr, OutputIterator out ) {
typedef typename detail::iterator_value_type<OutputIterator>::value_type OutputType; typedef typename detail::hex_iterator_traits<OutputIterator>::value_type OutputType;
// If we run into the terminator while decoding, we will throw a // If we run into the terminator while decoding, we will throw a
// malformed input exception. It would be nicer to throw a 'Not enough input' // malformed input exception. It would be nicer to throw a 'Not enough input'
// exception - but how much extra work would that require? // exception - but how much extra work would that require?
while ( *ptr ) while ( *ptr )
out = detail::decode_one ( ptr, (const T *) NULL, out ); out = detail::decode_one ( ptr, (const T *) NULL, out, detail::ptr_end<T> );
return out; return out;
} }

View File

@ -56,12 +56,25 @@ void test_short_input4 () {
BOOST_CHECK ( false ); BOOST_CHECK ( false );
} }
// Make sure that the right thing is thrown
void test_short_input5 () {
std::string s;
try { ba::unhex ( "A", std::back_inserter(s)); }
catch ( const ba::non_hex_input &ex ) { BOOST_CHECK ( false ); }
catch ( const ba::not_enough_input &ex ) { return; }
catch ( ... ) { BOOST_CHECK ( false ); }
BOOST_CHECK ( false );
}
void test_short_input () { void test_short_input () {
// BOOST_TEST_MESSAGE ( "Short input tests for boost::algorithm::unhex" ); // BOOST_TEST_MESSAGE ( "Short input tests for boost::algorithm::unhex" );
test_short_input1 (); test_short_input1 ();
test_short_input2 (); test_short_input2 ();
test_short_input3 (); test_short_input3 ();
test_short_input4 (); test_short_input4 ();
test_short_input5 ();
} }
@ -73,6 +86,7 @@ void test_nonhex_input1 () {
BOOST_CHECK ( 'G' == *boost::get_error_info<ba::bad_char>(ex)); BOOST_CHECK ( 'G' == *boost::get_error_info<ba::bad_char>(ex));
return; return;
} }
catch ( ... ) {}
BOOST_TEST_MESSAGE ( "Failed to catch std::exception in test_nonhex_input1" ); BOOST_TEST_MESSAGE ( "Failed to catch std::exception in test_nonhex_input1" );
BOOST_CHECK ( false ); BOOST_CHECK ( false );
} }
@ -85,6 +99,7 @@ void test_nonhex_input2 () {
BOOST_CHECK ( 'Z' == *boost::get_error_info<ba::bad_char>(ex)); BOOST_CHECK ( 'Z' == *boost::get_error_info<ba::bad_char>(ex));
return; return;
} }
catch ( ... ) {}
BOOST_TEST_MESSAGE ( "Failed to catch ba::hex_decode_error in test_nonhex_input2" ); BOOST_TEST_MESSAGE ( "Failed to catch ba::hex_decode_error in test_nonhex_input2" );
BOOST_CHECK ( false ); BOOST_CHECK ( false );
} }
@ -97,6 +112,7 @@ void test_nonhex_input3 () {
BOOST_CHECK ( 'Q' == *boost::get_error_info<ba::bad_char>(ex)); BOOST_CHECK ( 'Q' == *boost::get_error_info<ba::bad_char>(ex));
return; return;
} }
catch ( ... ) {}
BOOST_TEST_MESSAGE ( "Failed to catch ba::non_hex_input in test_nonhex_input3" ); BOOST_TEST_MESSAGE ( "Failed to catch ba::non_hex_input in test_nonhex_input3" );
BOOST_CHECK ( false ); BOOST_CHECK ( false );
} }
@ -112,30 +128,14 @@ void test_nonhex_input4 () {
BOOST_CHECK ( false ); BOOST_CHECK ( false );
} }
// Make sure that the right thing is thrown
void test_nonhex_input5 () {
std::string s;
try { ba::unhex ( "012", std::back_inserter(s)); }
catch ( const ba::non_hex_input &ex ) {
BOOST_CHECK ( '\000' == *boost::get_error_info<ba::bad_char>(ex));
return;
}
BOOST_TEST_MESSAGE ( "Failed to catch ba::non_hex_input in test_nonhex_input4" );
BOOST_CHECK ( false );
}
void test_nonhex_input () { void test_nonhex_input () {
// BOOST_TEST_MESSAGE ( "Non hex input tests for for boost::algorithm::unhex" ); // BOOST_TEST_MESSAGE ( "Non hex input tests for for boost::algorithm::unhex" );
test_nonhex_input1 (); test_nonhex_input1 ();
test_nonhex_input2 (); test_nonhex_input2 ();
test_nonhex_input3 (); test_nonhex_input3 ();
test_nonhex_input4 (); test_nonhex_input4 ();
test_nonhex_input5 ();
} }
int test_main( int , char* [] ) int test_main( int , char* [] )
{ {
test_short_input (); test_short_input ();