2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-25 23:02:38 +00:00
qpdf/libqpdf/bits.icc
Jay Berkenbilt 5d4cad9c02 ABI change: fix use of off_t, size_t, and integer types
Significantly improve the code's use of off_t for file offsets, size_t
for memory sizes, and integer types in cases where there has to be
compatibility with external interfaces.  Rework sections of the code
that would have prevented qpdf from working on files larger than 2 (or
maybe 4) GB in size.
2012-06-20 15:20:26 -04:00

150 lines
3.3 KiB
Plaintext

#ifndef __BITS_CC__
#define __BITS_CC__
#include <algorithm>
#include <stdexcept>
#include <qpdf/QTC.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 std::length_error("overflow reading bit stream");
}
if (bits_wanted > 32)
{
throw std::out_of_range("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 int bits, Pipeline* pipeline)
{
if (bits > 32)
{
throw std::out_of_range("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__