|
Boost-Commit : |
From: dwalker07_at_[hidden]
Date: 2008-08-13 15:05:50
Author: dlwalker
Date: 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
New Revision: 48131
URL: http://svn.boost.org/trac/boost/changeset/48131
Log:
Added Boost.Serialization support to selected classes, using XML archives for testing; ensured MD5-digest core header forward-declared (or defined) all related operators; touched-up Doxygen comments
Text files modified:
sandbox/md5/boost/coding/coding_shell.hpp | 64 ++++------------
sandbox/md5/boost/coding/md5_computer.hpp | 44 ++++++++---
sandbox/md5/boost/coding/md5_context.hpp | 103 +++++++++++++++++++++++++++
sandbox/md5/boost/coding/md5_digest_core.hpp | 12 +++
sandbox/md5/libs/coding/src/md5.cpp | 102 +++++++++++++++++++++++++++
sandbox/md5/libs/coding/test/md5_computer_test.cpp | 146 +++++++++++++++++++++++++++++++++++++--
6 files changed, 400 insertions(+), 71 deletions(-)
Modified: sandbox/md5/boost/coding/coding_shell.hpp
==============================================================================
--- sandbox/md5/boost/coding/coding_shell.hpp (original)
+++ sandbox/md5/boost/coding/coding_shell.hpp 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
@@ -18,12 +18,11 @@
#include <boost/coding_fwd.hpp>
-#include <boost/assert.hpp> // for BOOST_ASSERT
-#include <boost/mpl/bool.hpp> // for boost::mpl::bool_
-#include <boost/mpl/if.hpp> // for boost::mpl::if_
-#include <boost/mpl/int.hpp> // for boost::mpl::int_
-#include <boost/serialization/access.hpp> // for boost::serialization::access
-#include <boost/typeof/typeof.hpp> // for BOOST_AUTO
+#include <boost/assert.hpp> // for BOOST_ASSERT
+#include <boost/mpl/bool.hpp> // for boost::mpl::bool_
+#include <boost/mpl/if.hpp> // for boost::mpl::if_
+#include <boost/mpl/int.hpp> // for boost::mpl::int_
+#include <boost/typeof/typeof.hpp> // for BOOST_AUTO
#include <algorithm> // for std::copy, equal
#include <climits> // for CHAR_BIT
@@ -64,7 +63,6 @@
- a (<code>const</code>) member <code>operator
()</code> that takes nothing and returns a
\c product_type value.
- - serialization (through Boost.Serialization).
*/
template < class ByteProcessor >
class byte_coding_shell
@@ -151,15 +149,6 @@
//! Application
value_type operator ()() const;//@} // remove?
-private:
- /*! \name Persistence */ //@{
- // Serialization
- friend class boost::serialization::access;
-
- //! Enables persistence with Boost.Serialization-compatible archives
- template < class Archive >
- void serialize( Archive &ar, const unsigned int version );//@} // not defined yet
-
}; // byte_coding_shell
@@ -366,7 +355,6 @@
- a (<code>const</code>) member <code>operator
()</code> that takes nothing and returns a
\c product_type value.
- - serialization (through Boost.Serialization).
\tparam BigEndian The order the bits within a byte are processed. If
\c true, the most-significant bit of the byte is
processed first, going down to the least-significant
@@ -428,14 +416,6 @@
product_type operator ()() const;//@}
private:
- /*! \name Persistence */ //@{
- // Serialization
- friend class boost::serialization::access;
-
- //! Enables persistence with Boost.Serialization-compatible archives
- template < class Archive >
- void serialize( Archive &ar, const unsigned int version );//@} // not defined yet
-
// Bit-loop implementation
void consume_bits( unsigned char byte, int amount )
{
@@ -485,7 +465,7 @@
\post Calls <code>this->inner( <var>x</var> )</code> \c CHAR_BIT times,
with \p x iterating from either the highest-order bit (if
- \c #reads_start_highest is \c true) or lowest-order bit (if \c false)
+ \c #read_from_highest is \c true) or lowest-order bit (if \c false)
towards, and including, the opposite-order bit.
*/
template < class BitProcessor, bool BigEndian >
@@ -566,7 +546,6 @@
- a (<code>const</code>) member <code>operator
()</code> that takes nothing and returns a
\c product_type value.
- - serialization (through Boost.Serialization).
\tparam BigEndian The order the bits within a byte are processed. If
\c true, the most-significant bit of the byte is
processed first, going down to the least-significant
@@ -638,14 +617,14 @@
algorithms that return updated function objects to work.
\todo The current implementation stores a reference pointer to
- \c #bytes' wrapped engine, but copies of this sub-object will
- allocate (with regular <code>operator new</code>) independent
- copies of that engine. This will cause throws/crashes in
- situations when default memory allocation is full or disabled.
- (And there's no choice for an alternate allocation scheme.)
- Maybe a <code>boost::variant< BitProcessor *, BitProcessor
- ></code> can be used, but it has its own complicated storage
- issues, especially during assignment.
+ \c byte_coding_shell::bytes' wrapped engine, but copies of this
+ sub-object will allocate (with regular <code>operator new</code>)
+ independent copies of that engine. This will cause throws or
+ crashes in situations when default memory allocation is full or
+ disabled. (And there's no choice for an alternate allocation
+ scheme.) Maybe a <code>boost::variant< BitProcessor *,
+ BitProcessor ></code> can be used, but it has its own
+ complicated storage issues, especially during assignment.
*/
applicator bits;
@@ -676,15 +655,6 @@
//! Copy-assignment
self_type & operator =( self_type const &c );
-private:
- /*! \name Persistence */ //@{
- // Serialization
- friend class boost::serialization::access;
-
- //! Enables persistence with Boost.Serialization-compatible archives
- template < class Archive >
- void serialize( Archive &ar, const unsigned int version );//@} // not defined yet
-
}; // bit_coding_shell
@@ -767,9 +737,9 @@
\post Calls <code>this->bits( <var>x</var> )</code> \p bit_count times,
with \p x iterating from either the 2<sup><var>bit_count</var> -
- 1</sup>-place (if \c #reads_start_highest is \c true) or the
- ones-place (if \c false) towards, and including, the other mentioned
- bit. (If \p bit_count is zero, no calls are made.)
+ 1</sup>-place (if \c #read_from_highest is \c true) or the ones-place
+ (if \c false) towards, and including, the other mentioned bit. (If
+ \p bit_count is zero, no calls are made.)
*/
template < class BitProcessor, bool BigEndian >
inline void
Modified: sandbox/md5/boost/coding/md5_computer.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5_computer.hpp (original)
+++ sandbox/md5/boost/coding/md5_computer.hpp 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
@@ -28,6 +28,7 @@
#include <boost/cstdint.hpp> // for boost::uint_least8_t
#include <boost/integer/integer_mask.hpp> // for boost::integer_lo_mask
#include <boost/serialization/access.hpp> // for boost::serialization::access
+#include <boost/serialization/nvp.hpp> // for boost::serialization::make_nvp
#include <algorithm> // for std::copy, swap
@@ -141,8 +142,9 @@
// Serialization
friend class boost::serialization::access;
+ //! Enables persistence with Boost.Serialization-compatible archives
template < class Archive >
- void serialize( Archive &ar, const unsigned int version ); // not defined yet
+ void serialize( Archive &ar, const unsigned int version );
}; // md5_computer
@@ -163,8 +165,8 @@
}
/** Returns the checksum of all the bits that have been hashed so far. Hashing
- occurs only after every \c #bits_per_block::value bit entries, so check
- \c #bits_unbuffered() for any queued stragglers.
+ occurs only after every <code>#bits_per_block :: value</code> bit entries,
+ so check \c #bits_unbuffered() for any queued stragglers.
\return The current state of the MD buffer, not counting any unhashed bits.
*/
@@ -172,9 +174,9 @@
md5_computer::last_buffer() const { return this->context().buffer; }
/** Returns the number of bits that are still in the queue, unhashed. Hashing
- occurs only after every \c #bits_per_block::value bit submissions, so this
- member function can confirm queued stragglers. (The identities of hashed
- bits are not retrievable.)
+ occurs only after every <code>#bits_per_block :: value</code> bit
+ submissions, so this member function can confirm queued stragglers. (The
+ identities of hashed bits are not retrievable.)
\return How many bits are queued to be hashed.
@@ -187,8 +189,8 @@
/** Copies the last submitted bits that have not yet been hashed starting from
the oldest submission. Use \c #bits_unbuffered() for advance notice of how
- many iterations are done. (Always less than \c #bits_per_block::value
- elements are copied.)
+ many iterations are done. (Always less than <code>#bits_per_block ::
+ value</code> elements are copied.)
\pre At least \c #bits_unbuffered() more elements are free to be created
and/or assigned through \p o.
@@ -225,8 +227,6 @@
\post <code>#last_buffer() == { 0x67452301, 0xEFCDAB89, 0x98BACDFE,
0x10325476 }</code>.
\post <code>#copy_unbuffered(<var>o</var>)</code> leaves \p o unused.
-
- \see #md5_computer()
*/
inline void md5_computer::reset() { *this = self_type(); }
@@ -244,8 +244,6 @@
available, <code>std::equal( o1, o1 + bits_unbuffered(), o2 ) ==
true</code>.
\post \c #bits and \c #bytes \e still point to \c *this
-
- \see #md5_computer(md5_computer const&)
*/
inline void md5_computer::assign( self_type const &c ) { *this = c; }
@@ -315,7 +313,7 @@
the <code><var>old_this</var>.bits_unbuffered() + 32 -
bits_per_block</code> lowest-order bits of \p word.
- \see #process_octet(boost::uint_least8_t)
+ \see #process_octet(uint_least8_t)
*/
inline void
md5_computer::process_word( md5_digest::word_type word )
@@ -350,6 +348,26 @@
{ this->context().consume_dword( dword ); }
+// MD5 message-digest computation serialization function definition --------//
+
+/** Streams a computer to/from an archive using the Boost.Serialization
+ protocols. This member function is meant to be called only by the
+ Boost.Serialization system, as needed.
+
+ \tparam Archive The type of \p ar. It must conform to the requirements
+ Boost.Serialization expects of archiving classes.
+
+ \param ar The archiving object that this object's representation will
+ be streamed to/from.
+ \param version The version of the persistence format for this object. (It
+ should be zero, since this type just got created.)
+ */
+template < class Archive >
+inline void
+md5_computer::serialize( Archive &ar, const unsigned int version )
+{ ar & boost::serialization::make_nvp( "context", this->context() ); }
+
+
// MD5 message-digest computation miscellaneous function definitions -------//
/** \brief Non-member swapping function for \c md5_computer
Modified: sandbox/md5/boost/coding/md5_context.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5_context.hpp (original)
+++ sandbox/md5/boost/coding/md5_context.hpp 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
@@ -27,9 +27,12 @@
#include <boost/mpl/times.hpp> // for boost::mpl::times
#include <boost/mpl/int.hpp> // for boost::mpl::int_
-#include <boost/serialization/access.hpp> // for boost::serialization::access
+#include <boost/serialization/access.hpp> // for boost::s11n::access
+#include <boost/serialization/nvp.hpp> // for boost::s11n::make_nvp
+#include <boost/serialization/split_member.hpp> // for boost:s11n:split_member
#include <algorithm> // for std::equal, copy
+#include <string> // for std::string
namespace boost
@@ -127,8 +130,18 @@
// Serialization
friend class boost::serialization::access;
+ std::string queue_to_string() const;
+ void string_to_queue( std::string const &s );
+
+ //! Write serialization
+ template < class Archive >
+ void save( Archive &ar, const unsigned int version ) const;
+ //! Read serialization
+ template < class Archive >
+ void load( Archive &ar, const unsigned int version );
+ //! Enables persistence with Boost.Serialization-compatible archives
template < class Archive >
- void serialize( Archive &ar, const unsigned int version );//@} // not defined yet
+ void serialize( Archive &ar, const unsigned int version );//@}
}; // md5_context
@@ -232,6 +245,92 @@
this->consume_word( dword & 0xFFFFFFFFul );
}
+/** Perserves a core computer to a serialization streamed to an archive using
+ the Boost.Serialization protocols. This member function is meant to be
+ called only by the Boost.Serialization system, as needed.
+
+ \tparam Archive The type of \p ar. It must conform to the requirements
+ Boost.Serialization expects of archiving classes.
+
+ \param ar The archiving object that this object's representation will
+ be streamed to.
+ \param version The version of the persistence format for this object. (It
+ should be zero, since this type just got created.)
+ */
+template < class Archive >
+void
+md5_context::save( Archive &ar, const unsigned int version ) const
+{
+ using boost::serialization::make_nvp;
+
+ std::string const queue_string = this->queue_to_string();
+
+ switch ( version )
+ {
+ default:
+ case 0u:
+ ar << make_nvp( "length", this->length )
+ << make_nvp( "buffer-A", this->buffer[0] )
+ << make_nvp( "buffer-B", this->buffer[1] )
+ << make_nvp( "buffer-C", this->buffer[2] )
+ << make_nvp( "buffer-D", this->buffer[3] )
+ << make_nvp( "message-tail", queue_string );
+ break;
+ }
+}
+
+/** Resets a core computer to a serialization streamed from an archive using the
+ Boost.Serialization protocols. This member function is meant to be called
+ only by the Boost.Serialization system, as needed.
+
+ \tparam Archive The type of \p ar. It must conform to the requirements
+ Boost.Serialization expects of archiving classes.
+
+ \param ar The archiving object that this object's representation will
+ be streamed from.
+ \param version The version of the persistence format for this object. (It
+ should be zero, since this type just got created.)
+ */
+template < class Archive >
+void
+md5_context::load( Archive &ar, const unsigned int version )
+{
+ using boost::serialization::make_nvp;
+
+ std::string queue_string;
+
+ switch ( version )
+ {
+ default:
+ case 0u:
+ ar >> make_nvp( "length", this->length )
+ >> make_nvp( "buffer-A", this->buffer[0] )
+ >> make_nvp( "buffer-B", this->buffer[1] )
+ >> make_nvp( "buffer-C", this->buffer[2] )
+ >> make_nvp( "buffer-D", this->buffer[3] )
+ >> make_nvp( "message-tail", queue_string );
+ this->string_to_queue( queue_string );
+ break;
+ }
+}
+
+/** Streams a core computer to/from an archive using the Boost.Serialization
+ protocols. This member function is meant to be called only by the
+ Boost.Serialization system, as needed.
+
+ \tparam Archive The type of \p ar. It must conform to the requirements
+ Boost.Serialization expects of archiving classes.
+
+ \param ar The archiving object that this object's representation will
+ be streamed to/from.
+ \param version The version of the persistence format for this object. (It
+ should be zero, since this type just got created.)
+ */
+template < class Archive >
+inline void
+md5_context::serialize( Archive &ar, const unsigned int version )
+{ boost::serialization::split_member( ar, *this, version ); }
+
} // namespace coding
} // namespace boost
Modified: sandbox/md5/boost/coding/md5_digest_core.hpp
==============================================================================
--- sandbox/md5/boost/coding/md5_digest_core.hpp (original)
+++ sandbox/md5/boost/coding/md5_digest_core.hpp 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
@@ -23,6 +23,7 @@
#include <boost/mpl/size_t.hpp> // for boost::mpl::size_t
#include <algorithm> // for std::equal
+#include <iosfwd> // for std::basic_istream, basic_ostream (declarations)
namespace boost
@@ -31,6 +32,17 @@
{
+// Forward declarations ----------------------------------------------------//
+
+// I/O streaming operator functions
+template < typename Ch, class Tr >
+ std::basic_istream<Ch, Tr> & operator >>( std::basic_istream<Ch, Tr> &i,
+ md5_digest &n );
+template < typename Ch, class Tr >
+ std::basic_ostream<Ch, Tr> & operator <<( std::basic_ostream<Ch, Tr> &o,
+ md5_digest const &n );
+
+
// MD5 message-digest class declaration ------------------------------------//
/** \brief A class for storing a MD5 message digest.
Modified: sandbox/md5/libs/coding/src/md5.cpp
==============================================================================
--- sandbox/md5/libs/coding/src/md5.cpp (original)
+++ sandbox/md5/libs/coding/src/md5.cpp 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
@@ -21,6 +21,7 @@
#include <boost/array.hpp> // for boost::array
#include <boost/assert.hpp> // for BOOST_ASSERT
+#include <boost/bimap.hpp> // for boost::bimap
#include <boost/integer/integer_mask.hpp> // for boost::integer_lo_mask
#include <boost/limits.hpp> // for std::numeric_limits
#include <boost/math/common_factor_rt.hpp> // for boost::math::gcd
@@ -30,6 +31,7 @@
#include <cmath> // for std::sin, abs, ldexp, modf
#include <cstddef> // for std::size_t
#include <numeric> // for std::inner_product, partial_sum
+#include <string> // for std::string
#include <valarray> // for std::valarray, etc.
@@ -173,6 +175,34 @@
return r;
}
+// Convert an array, which maps an index to a value, to a bimap so the index can
+// be found given a value. This assumes that each array element is unique.
+template < typename T, std::size_t N >
+boost::bimap<std::size_t, T> array_to_bimap( T const (&array)[N] )
+{
+ typedef boost::bimap<std::size_t, T> result_type;
+ typedef typename result_type::value_type value_type;
+
+ result_type result;
+
+ for ( std::size_t i = 0u ; i < N ; ++i )
+ result.insert( value_type(i, array[ i ]) );
+ BOOST_ASSERT( result.size() == N );
+ return result;
+}
+
+// This is the "base64url" encoding; see RFC 4648, section 5
+char const base64url_str[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+char const (&base64url)[64] = *reinterpret_cast<char const (*)[64]>(
+ &base64url_str );
+char const base64url_pad = '=';
+
+// Now make that encoding searchable both ways
+typedef boost::bimap<std::size_t, char> base64url_map_t;
+
+base64url_map_t const base64url_map = array_to_bimap( base64url );
+
} // unnamed namespace
@@ -380,6 +410,78 @@
// Now a finished checksum in this->buffer is ready to read.
}
+// Convert the current queue to a string to serialize
+std::string md5_context::queue_to_string() const
+{
+ using std::size_t;
+
+ size_t const unbuffered = this->length % bits_per_block::value,
+ bits_per_sextet = 6,
+ full_sextets = unbuffered / bits_per_sextet,
+ leftover_bits = unbuffered % bits_per_sextet,
+ partial_sextet = ( leftover_bits != 0u );
+ bool const * i = this->queue.begin();
+ size_t index;
+ std::string result;
+
+ result.reserve( full_sextets + partial_sextet );
+
+ for ( size_t j = 0u ; j < full_sextets ; ++j )
+ {
+ // leading Booleans get high-order spots
+ index = 0u;
+ for ( size_t k = 0u ; k < bits_per_sextet ; ++k )
+ {
+ index <<= 1;
+ if ( *i++ ) index |= 1u;
+ }
+ result.push_back( base64url[index] );
+ }
+
+ if ( partial_sextet )
+ {
+ index = 0u;
+ for ( size_t l = 0u ; l < leftover_bits ; ++l )
+ {
+ index <<= 1;
+ if ( *i++ ) index |= 1u;
+ }
+
+ // Fill in remaining spots of this sextet
+ index <<= bits_per_sextet - leftover_bits;
+ result.push_back( base64url[index] );
+ }
+
+ return result;
+}
+
+// Convert an unserialized string back to a queue state
+void md5_context::string_to_queue( std::string const &s )
+{
+ using std::size_t;
+
+ size_t const bits_per_sextet = 6;
+ bool * i = this->queue.begin();
+ int limit = bits_per_block::value; // resolves partial sextets
+
+ for ( std::string::const_iterator si = s.begin(), se = s.end() ; (si != se)
+ && (limit > 0) ; ++si )
+ {
+ // Skip over any illegal characters
+ base64url_map_t::right_const_iterator const p_index =
+ base64url_map.right.find( *si );
+
+ if ( p_index == base64url_map.right.end() ) continue;
+
+ // Insert the bits expanded from the index
+ size_t const mask = 1u << ( bits_per_sextet - 1u );
+
+ for ( size_t j = 0u, index = p_index->second ; (j < bits_per_sextet) &&
+ (limit-- > 0) ; ++j, index <<= 1 )
+ *i++ = index & mask;
+ }
+}
+
// MD5 message-digest computation non-inline member definitions ------------//
Modified: sandbox/md5/libs/coding/test/md5_computer_test.cpp
==============================================================================
--- sandbox/md5/libs/coding/test/md5_computer_test.cpp (original)
+++ sandbox/md5/libs/coding/test/md5_computer_test.cpp 2008-08-13 15:05:49 EDT (Wed, 13 Aug 2008)
@@ -15,9 +15,32 @@
#include <boost/lexical_cast.hpp> // for boost::lexical_cast
#include <boost/test/unit_test.hpp> // unit testing framework
+#include <boost/archive/xml_iarchive.hpp> // for boost::archive::xml_iarchive
+#include <boost/archive/xml_oarchive.hpp> // for boost::archive::xml_oarchive
+#include <boost/serialization/nvp.hpp> // for boost::serialization::make_nvp
+
#include <algorithm> // for std::reverse, for_each
#include <climits> // for CHAR_BIT
#include <cstddef> // for std::size_t
+#include <iostream> // for std::cout
+#include <istream> // for std::basic_istream
+#include <ostream> // for std::endl, basic_ostream
+#include <sstream> // for std::stringstream
+
+
+// Control if XML code will be printed conventionally, or just logged.
+#ifndef CONTROL_SHOW_XML
+#define CONTROL_SHOW_XML 0
+#endif
+
+// Logging
+#if CONTROL_SHOW_XML
+#define PRIVATE_SHOW_MESSAGE( m ) std::cout << m << std::endl
+#else
+#define PRIVATE_SHOW_MESSAGE( m ) BOOST_TEST_MESSAGE( m )
+#endif
+
+BOOST_TEST_DONT_PRINT_LOG_VALUE( boost::coding::md5_computer );
#pragma mark Intro stuff
@@ -44,6 +67,26 @@
md5_digest const md5_empty_data = { {0xD98C1DD4ul, 0x04B2008Ful, 0x980980E9ul,
0x7E42F8ECul} }; // see md5_empty
+// Completely read an archive from a stream
+template < typename Ch, class Tr, typename T >
+void read_xml_archive( std::basic_istream<Ch, Tr> &i, T &target, char const
+ *name )
+{
+ boost::archive::xml_iarchive ar( i );
+
+ ar >> boost::serialization::make_nvp( name, target );
+}
+
+// Completely write an archive to a stream
+template < typename Ch, class Tr, typename T >
+void write_xml_archive( std::basic_ostream<Ch, Tr> &o, T const &target, char
+ const *name )
+{
+ boost::archive::xml_oarchive ar( o );
+
+ ar << boost::serialization::make_nvp( name, target );
+}
+
} // unnamed namespace
@@ -544,15 +587,100 @@
BOOST_CHECK( c4 == c3 );
}
-// Output archiving test
-//BOOST_AUTO_TEST_CASE( md5_computer_output_test )
-//{
-//}
-
-// Input archiving test
-//BOOST_AUTO_TEST_CASE( md5_computer_input_test )
-//{
-//}
+// Archiving test
+BOOST_AUTO_TEST_CASE( md5_computer_serialization_test )
+{
+ // Make differing computers, to compare/contrast against a test computer
+ md5_computer c1, c2;
+
+ c2.bits( true );
+ BOOST_REQUIRE_NE( c1, c2 );
+
+ md5_computer test = c2;
+
+ BOOST_REQUIRE_NE( test, c1 );
+ BOOST_REQUIRE_EQUAL( test, c2 );
+
+ // Write to an archive
+ std::stringstream ss;
+ write_xml_archive( ss, test, "test" );
+
+ // Reset the test computer to ensure reading works
+ test.reset();
+ BOOST_REQUIRE_EQUAL( test, c1 );
+ BOOST_REQUIRE_NE( test, c2 );
+
+ // Read from an archive
+ PRIVATE_SHOW_MESSAGE( ss.str() );
+ read_xml_archive( ss, test, "test" );
+
+ // Confirm the change and proper read-back
+ BOOST_CHECK_NE( test, c1 );
+ BOOST_CHECK_EQUAL( test, c2 );
+
+ // Do tests again, but use exactly 6 bits total
+ c2.process_bits( 0x0Au, 5u );
+ BOOST_REQUIRE_EQUAL( c2.bits_read(), 6u );
+
+ test.assign( c2 );
+ ss.str( "" );
+ write_xml_archive( ss, test, "test" );
+ test.reset();
+ BOOST_REQUIRE_NE( test, c2 );
+ PRIVATE_SHOW_MESSAGE( ss.str() );
+ read_xml_archive( ss, test, "test" );
+ BOOST_CHECK_EQUAL( test, c2 );
+
+ // Now try whole and partial bit-sextets
+ c2.process_octet( 66 ); // 'B' in ASCII
+ BOOST_REQUIRE_EQUAL( c2.bits_read(), 14u );
+
+ test.assign( c2 );
+ ss.str( "" );
+ write_xml_archive( ss, test, "test" );
+ test.reset();
+ BOOST_REQUIRE_NE( test, c2 );
+ PRIVATE_SHOW_MESSAGE( ss.str() );
+ read_xml_archive( ss, test, "test" );
+ BOOST_CHECK_EQUAL( test, c2 );
+
+ // Rig a result that gives all the Base-64 (URL style) characters, plus fill
+ // the queue to just below full. (Full would immediately reset the queue to
+ // empty.) That way, the last character should contain extra bits that
+ // definately shouldn't be copied down. (It would lead to an access error.)
+ int const block_size = md5_computer::bits_per_block::value;
+ BOOST_REQUIRE_NE( (block_size - 1) % 6, 0 );
+ BOOST_REQUIRE_GE( 6 - (block_size - 1) % 6, 3 );
+
+ c2.reset();
+ for ( int i = 0 ; i < 64 ; ++i ) c2.process_bits( i, 6 );
+ c2.process_bit_copies( false, (block_size - 1 - c2.bits_read()) / 2 );
+ c2.process_bit_copies( true, block_size - 1 - c2.bits_read() );
+ BOOST_REQUIRE_EQUAL( c2.bits_read(), block_size - 1 );
+
+ test.assign( c2 );
+ ss.str( "" );
+ write_xml_archive( ss, test, "test" );
+ test.reset();
+ BOOST_REQUIRE_NE( test, c2 );
+ PRIVATE_SHOW_MESSAGE( ss.str() );
+ read_xml_archive( ss, test, "test" );
+ BOOST_CHECK_EQUAL( test, c2 );
+
+ // Now turn over the queue, hopefully see an empty string
+ c2.process_bit( false );
+ BOOST_REQUIRE_EQUAL( c2.bits_read(), block_size );
+ BOOST_REQUIRE_EQUAL( c2.bits_unbuffered(), 0u );
+
+ test.assign( c2 );
+ ss.str( "" );
+ write_xml_archive( ss, test, "test" );
+ test.reset();
+ BOOST_REQUIRE_NE( test, c2 );
+ PRIVATE_SHOW_MESSAGE( ss.str() );
+ read_xml_archive( ss, test, "test" );
+ BOOST_CHECK_EQUAL( test, c2 );
+}
// Single-call function test
BOOST_AUTO_TEST_CASE( compute_md5_test )
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk