aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/bits.icc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/bits.icc')
-rw-r--r--libqpdf/bits.icc149
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__