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