Boost logo

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-&gt;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&lt; BitProcessor *, BitProcessor
- &gt;</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&lt; BitProcessor *,
+ BitProcessor &gt;</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-&gt;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