diff options
Diffstat (limited to 'libqpdf/bits.icc')
-rw-r--r-- | libqpdf/bits.icc | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/libqpdf/bits.icc b/libqpdf/bits.icc new file mode 100644 index 00000000..465bf5b9 --- /dev/null +++ b/libqpdf/bits.icc @@ -0,0 +1,149 @@ + +#ifndef __BITS_CC__ +#define __BITS_CC__ + +#include <algorithm> +#include <qpdf/QTC.hh> +#include <qpdf/QEXC.hh> +#include <qpdf/Pipeline.hh> + +// These functions may be run at places where the function call +// overhead from test coverage testing would be too high. Therefore, +// we make the test coverage cases conditional upon a preprocessor +// symbol. BitStream.cc includes this file without defining the +// symbol, and the specially designed test code that fully exercises +// this code includes with the symbol defined. + +#ifdef BITS_READ +static unsigned long +read_bits(unsigned char const*& p, unsigned int& bit_offset, + unsigned int& bits_available, unsigned int bits_wanted) +{ + // View p as a stream of bits: + + // 76543210 76543210 .... + + // bit_offset is the bit number within the first byte that marks + // the first bit that we would read. + + if (bits_wanted > bits_available) + { + throw QEXC::General("overflow reading bit stream"); + } + if (bits_wanted > 32) + { + throw QEXC::Internal("read_bits: too many bits requested"); + } + + unsigned long result = 0; +#ifdef BITS_TESTING + if (bits_wanted == 0) + { + QTC::TC("libtests", "bits zero bits wanted"); + } +#endif + while (bits_wanted > 0) + { + // Grab bits from the first byte clearing anything before + // bit_offset. + unsigned char byte = *p & ((1 << (bit_offset + 1)) - 1); + + // There are bit_offset + 1 bits available in the first byte. + unsigned int to_copy = std::min(bits_wanted, bit_offset + 1); + unsigned int leftover = (bit_offset + 1) - to_copy; + +#ifdef BITS_TESTING + QTC::TC("libtests", "bits bit_offset", + ((bit_offset == 0) ? 0 : + (bit_offset == 7) ? 1 : + 2)); + QTC::TC("libtests", "bits leftover", (leftover > 0) ? 1 : 0); +#endif + + // Right shift so that all the bits we want are right justified. + byte >>= leftover; + + // Copy the bits into result + result <<= to_copy; + result |= byte; + + // Update pointers + if (leftover) + { + bit_offset = leftover - 1; + } + else + { + bit_offset = 7; + ++p; + } + bits_wanted -= to_copy; + bits_available -= to_copy; + +#ifdef BITS_TESTING + QTC::TC("libtests", "bits iterations", + ((bits_wanted > 8) ? 0 : + (bits_wanted > 0) ? 1 : + 2)); +#endif + } + + return result; +} +#endif + +#ifdef BITS_WRITE +static void +write_bits(unsigned char& ch, unsigned int& bit_offset, + unsigned long val, unsigned bits, Pipeline* pipeline) +{ + if (bits > 32) + { + throw QEXC::Internal("write_bits: too many bits requested"); + } + + // bit_offset + 1 is the number of bits left in ch +#ifdef BITS_TESTING + if (bits == 0) + { + QTC::TC("libtests", "bits write zero bits"); + } +#endif + while (bits > 0) + { + int bits_to_write = std::min(bits, bit_offset + 1); + unsigned char newval = + (val >> (bits - bits_to_write)) & ((1 << bits_to_write) - 1); + int bits_left_in_ch = bit_offset + 1 - bits_to_write; + newval <<= bits_left_in_ch; + ch |= newval; + if (bits_left_in_ch == 0) + { +#ifdef BITS_TESTING + QTC::TC("libtests", "bits write pipeline"); +#endif + pipeline->write(&ch, 1); + bit_offset = 7; + ch = 0; + } + else + { +#ifdef BITS_TESTING + QTC::TC("libtests", "bits write leftover"); +#endif + bit_offset -= bits_to_write; + } + bits -= bits_to_write; +#ifdef BITS_TESTING + QTC::TC("libtests", "bits write iterations", + ((bits > 8) ? 0 : + (bits > 0) ? 1 : + 2)); +#endif + } + +} +#endif + + +#endif // __BITS_CC__ |