@@ -510,12 +510,105 @@ class CDataStream
510
510
}
511
511
};
512
512
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;
513
561
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 };
514
565
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 };
515
570
571
+ public:
572
+ explicit BitStreamWriter (OStream& ostream) : m_ostream(ostream) {}
516
573
574
+ ~BitStreamWriter ()
575
+ {
576
+ Flush ();
577
+ }
517
578
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;
518
592
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
+ };
519
612
520
613
521
614
0 commit comments