diff --git a/include/boost/algorithm/hex.hpp b/include/boost/algorithm/hex.hpp index b6b1548..3f3c0c6 100644 --- a/include/boost/algorithm/hex.hpp +++ b/include/boost/algorithm/hex.hpp @@ -110,33 +110,25 @@ namespace detail { 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 struct value_type_or_char { typedef T value_type; }; - template <> struct value_type_or_char { typedef char value_type; }; - -// All in one step - template - struct iterator_value_type { -// typedef typename value_type_or_char::value_type>::value_type value_type; - typedef typename hex_iterator_traits::value_type value_type; - }; - + template + bool iter_end ( Iterator current, Iterator last ) { return current == last; } + + template + bool ptr_end ( const T* ptr, const T* /*end*/ ) { return *ptr == '\0'; } + // What can we assume here about the inputs? // is std::iterator_traits::value_type always 'char' ? // Could it be wchar_t, say? Does it matter? // We are assuming ASCII for the values - but what about the storage? - template - typename boost::enable_if::value_type>, OutputIterator>::type - decode_one ( InputIterator &first, InputIterator last, OutputIterator out ) { - typedef typename iterator_value_type::value_type T; + template + typename boost::enable_if::value_type>, OutputIterator>::type + decode_one ( InputIterator &first, InputIterator last, OutputIterator out, EndPred pred ) { + typedef typename hex_iterator_traits::value_type T; T res (0); // 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 ( first == last ) + if ( pred ( first, last )) BOOST_THROW_EXCEPTION (not_enough_input ()); res = ( 16 * res ) + hex_char_to_int (static_cast (*first)); } @@ -205,7 +197,7 @@ hex ( const Range &r, OutputIterator out ) { template OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator out ) { while ( first != last ) - out = detail::decode_one ( first, last, out ); + out = detail::decode_one ( first, last, out, detail::iter_end ); return out; } @@ -219,12 +211,12 @@ OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator o /// \note Based on the MySQL function of the same name template OutputIterator unhex ( const T *ptr, OutputIterator out ) { - typedef typename detail::iterator_value_type::value_type OutputType; + typedef typename detail::hex_iterator_traits::value_type OutputType; // 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' // exception - but how much extra work would that require? while ( *ptr ) - out = detail::decode_one ( ptr, (const T *) NULL, out ); + out = detail::decode_one ( ptr, (const T *) NULL, out, detail::ptr_end ); return out; } diff --git a/test/hex_test4.cpp b/test/hex_test4.cpp index 7b22b64..cf20431 100644 --- a/test/hex_test4.cpp +++ b/test/hex_test4.cpp @@ -56,12 +56,25 @@ void test_short_input4 () { 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 () { // BOOST_TEST_MESSAGE ( "Short input tests for boost::algorithm::unhex" ); test_short_input1 (); test_short_input2 (); test_short_input3 (); test_short_input4 (); + test_short_input5 (); } @@ -73,6 +86,7 @@ void test_nonhex_input1 () { BOOST_CHECK ( 'G' == *boost::get_error_info(ex)); return; } + catch ( ... ) {} BOOST_TEST_MESSAGE ( "Failed to catch std::exception in test_nonhex_input1" ); BOOST_CHECK ( false ); } @@ -85,6 +99,7 @@ void test_nonhex_input2 () { BOOST_CHECK ( 'Z' == *boost::get_error_info(ex)); return; } + catch ( ... ) {} BOOST_TEST_MESSAGE ( "Failed to catch ba::hex_decode_error in test_nonhex_input2" ); BOOST_CHECK ( false ); } @@ -97,6 +112,7 @@ void test_nonhex_input3 () { BOOST_CHECK ( 'Q' == *boost::get_error_info(ex)); return; } + catch ( ... ) {} BOOST_TEST_MESSAGE ( "Failed to catch ba::non_hex_input in test_nonhex_input3" ); BOOST_CHECK ( false ); } @@ -112,30 +128,14 @@ void test_nonhex_input4 () { 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(ex)); - return; - } - BOOST_TEST_MESSAGE ( "Failed to catch ba::non_hex_input in test_nonhex_input4" ); - BOOST_CHECK ( false ); - } - void test_nonhex_input () { // BOOST_TEST_MESSAGE ( "Non hex input tests for for boost::algorithm::unhex" ); test_nonhex_input1 (); test_nonhex_input2 (); test_nonhex_input3 (); test_nonhex_input4 (); - test_nonhex_input5 (); } - - int test_main( int , char* [] ) { test_short_input ();