1 2#ifndef __BITS_CC__ 3#define __BITS_CC__ 4 5#include <algorithm> 6#include <stdexcept> 7#include <qpdf/QTC.hh> 8#include <qpdf/Pipeline.hh> 9#include <qpdf/QUtil.hh> 10 11// These functions may be run at places where the function call 12// overhead from test coverage testing would be too high. Therefore, 13// we make the test coverage cases conditional upon a preprocessor 14// symbol. BitStream.cc includes this file without defining the 15// symbol, and the specially designed test code that fully exercises 16// this code includes with the symbol defined. 17 18#ifdef BITS_READ 19static unsigned long long 20read_bits(unsigned char const*& p, size_t& bit_offset, 21 size_t& bits_available, size_t bits_wanted) 22{ 23 // View p as a stream of bits: 24 25 // 76543210 76543210 .... 26 27 // bit_offset is the bit number within the first byte that marks 28 // the first bit that we would read. 29 30 if (bits_wanted > bits_available) 31 { 32 throw std::runtime_error( 33 "overflow reading bit stream: wanted = " + 34 QUtil::uint_to_string(bits_wanted) + "; available = " + 35 QUtil::uint_to_string(bits_available)); 36 } 37 if (bits_wanted > 32) 38 { 39 throw std::out_of_range("read_bits: too many bits requested"); 40 } 41 42 unsigned long result = 0; 43#ifdef BITS_TESTING 44 if (bits_wanted == 0) 45 { 46 QTC::TC("libtests", "bits zero bits wanted"); 47 } 48#endif 49 while (bits_wanted > 0) 50 { 51 // Grab bits from the first byte clearing anything before 52 // bit_offset. 53 unsigned char byte = static_cast<unsigned char>( 54 *p & ((1U << (bit_offset + 1U)) - 1U)); 55 56 // There are bit_offset + 1 bits available in the first byte. 57 size_t to_copy = std::min(bits_wanted, bit_offset + 1); 58 size_t leftover = (bit_offset + 1) - to_copy; 59 60#ifdef BITS_TESTING 61 QTC::TC("libtests", "bits bit_offset", 62 ((bit_offset == 0) ? 0 : 63 (bit_offset == 7) ? 1 : 64 2)); 65 QTC::TC("libtests", "bits leftover", (leftover > 0) ? 1 : 0); 66#endif 67 68 // Right shift so that all the bits we want are right justified. 69 byte = static_cast<unsigned char>(byte >> leftover); 70 71 // Copy the bits into result 72 result <<= to_copy; 73 result |= byte; 74 75 // Update pointers 76 if (leftover) 77 { 78 bit_offset = leftover - 1; 79 } 80 else 81 { 82 bit_offset = 7; 83 ++p; 84 } 85 bits_wanted -= to_copy; 86 bits_available -= to_copy; 87 88#ifdef BITS_TESTING 89 QTC::TC("libtests", "bits iterations", 90 ((bits_wanted > 8) ? 0 : 91 (bits_wanted > 0) ? 1 : 92 2)); 93#endif 94 } 95 96 return result; 97} 98#endif 99 100#ifdef BITS_WRITE 101static void 102write_bits(unsigned char& ch, size_t& bit_offset, 103 unsigned long long val, size_t bits, Pipeline* pipeline) 104{ 105 if (bits > 32) 106 { 107 throw std::out_of_range("write_bits: too many bits requested"); 108 } 109 110 // bit_offset + 1 is the number of bits left in ch 111#ifdef BITS_TESTING 112 if (bits == 0) 113 { 114 QTC::TC("libtests", "bits write zero bits"); 115 } 116#endif 117 while (bits > 0) 118 { 119 size_t bits_to_write = std::min(bits, bit_offset + 1); 120 unsigned char newval = static_cast<unsigned char>( 121 (val >> (bits - bits_to_write)) & ((1U << bits_to_write) - 1)); 122 size_t bits_left_in_ch = bit_offset + 1 - bits_to_write; 123 newval = static_cast<unsigned char>(newval << bits_left_in_ch); 124 ch |= newval; 125 if (bits_left_in_ch == 0) 126 { 127#ifdef BITS_TESTING 128 QTC::TC("libtests", "bits write pipeline"); 129#endif 130 pipeline->write(&ch, 1); 131 bit_offset = 7; 132 ch = 0; 133 } 134 else 135 { 136#ifdef BITS_TESTING 137 QTC::TC("libtests", "bits write leftover"); 138#endif 139 bit_offset -= bits_to_write; 140 } 141 bits -= bits_to_write; 142#ifdef BITS_TESTING 143 QTC::TC("libtests", "bits write iterations", 144 ((bits > 8) ? 0 : 145 (bits > 0) ? 1 : 146 2)); 147#endif 148 } 149 150} 151#endif 152 153 154#endif // __BITS_CC__ 155