@@ -510,12 +510,105 @@ class CDataStream
510510 }
511511};
512512
513+ template <typename IStream>
514+ class BitStreamReader
515+ {
516+ private:
517+ IStream& m_istream;
518+
519+ // / Buffered byte read in from the input stream. A new byte is read into the
520+ // / buffer when m_offset reaches 8.
521+ uint8_t m_buffer{0 };
522+
523+ // / Number of high order bits in m_buffer already returned by previous
524+ // / Read() calls. The next bit to be returned is at this offset from the
525+ // / most significant bit position.
526+ int m_offset{8 };
527+
528+ public:
529+ explicit BitStreamReader (IStream& istream) : m_istream(istream) {}
530+
531+ /* * Read the specified number of bits from the stream. The data is returned
532+ * in the nbits least signficant bits of a 64-bit uint.
533+ */
534+ uint64_t Read (int nbits) {
535+ if (nbits < 0 || nbits > 64 ) {
536+ throw std::out_of_range (" nbits must be between 0 and 64" );
537+ }
538+
539+ uint64_t data = 0 ;
540+ while (nbits > 0 ) {
541+ if (m_offset == 8 ) {
542+ m_istream >> m_buffer;
543+ m_offset = 0 ;
544+ }
545+
546+ int bits = std::min (8 - m_offset, nbits);
547+ data <<= bits;
548+ data |= static_cast <uint8_t >(m_buffer << m_offset) >> (8 - bits);
549+ m_offset += bits;
550+ nbits -= bits;
551+ }
552+ return data;
553+ }
554+ };
555+
556+ template <typename OStream>
557+ class BitStreamWriter
558+ {
559+ private:
560+ OStream& m_ostream;
513561
562+ // / Buffered byte waiting to be written to the output stream. The byte is
563+ // / written buffer when m_offset reaches 8 or Flush() is called.
564+ uint8_t m_buffer{0 };
514565
566+ // / Number of high order bits in m_buffer already written by previous
567+ // / Write() calls and not yet flushed to the stream. The next bit to be
568+ // / written to is at this offset from the most significant bit position.
569+ int m_offset{0 };
515570
571+ public:
572+ explicit BitStreamWriter (OStream& ostream) : m_ostream(ostream) {}
516573
574+ ~BitStreamWriter ()
575+ {
576+ Flush ();
577+ }
517578
579+ /* * Write the nbits least significant bits of a 64-bit int to the output
580+ * stream. Data is buffered until it completes an octet.
581+ */
582+ void Write (uint64_t data, int nbits) {
583+ if (nbits < 0 || nbits > 64 ) {
584+ throw std::out_of_range (" nbits must be between 0 and 64" );
585+ }
586+
587+ while (nbits > 0 ) {
588+ int bits = std::min (8 - m_offset, nbits);
589+ m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
590+ m_offset += bits;
591+ nbits -= bits;
518592
593+ if (m_offset == 8 ) {
594+ Flush ();
595+ }
596+ }
597+ }
598+
599+ /* * Flush any unwritten bits to the output stream, padding with 0's to the
600+ * next byte boundary.
601+ */
602+ void Flush () {
603+ if (m_offset == 0 ) {
604+ return ;
605+ }
606+
607+ m_ostream << m_buffer;
608+ m_buffer = 0 ;
609+ m_offset = 0 ;
610+ }
611+ };
519612
520613
521614
0 commit comments