Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
BitReader
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
5 / 5
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 readBits
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 alignToByte
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getBitPosition
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBytePosition
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Pdf\Reader\Parser;
6
7/**
8 * Reads variable-width bit fields from a binary buffer.
9 *
10 * Used by the hint table parser to decode the bit-packed per-page
11 * and shared-object entries defined in ISO 32000-2 Annex F.
12 */
13final class BitReader
14{
15    private int $bitPos = 0;
16
17    public function __construct(private readonly string $data) {}
18
19    /**
20     * Read an unsigned integer of the given bit width.
21     *
22     * @param int $count Number of bits to read (0–32)
23     */
24    public function readBits(int $count): int
25    {
26        if ($count === 0) {
27            return 0;
28        }
29
30        $result = 0;
31        for ($i = 0; $i < $count; $i++) {
32            $byteIndex = intdiv($this->bitPos, 8);
33            $bitIndex = 7 - ($this->bitPos % 8); // MSB first
34
35            if ($byteIndex >= strlen($this->data)) {
36                throw new \RuntimeException('BitReader: read past end of data');
37            }
38
39            $bit = (ord($this->data[$byteIndex]) >> $bitIndex) & 1;
40            $result = ($result << 1) | $bit;
41            $this->bitPos++;
42        }
43
44        return $result;
45    }
46
47    /** Advance to the next byte boundary. */
48    public function alignToByte(): void
49    {
50        $remainder = $this->bitPos % 8;
51        if ($remainder !== 0) {
52            $this->bitPos += (8 - $remainder);
53        }
54    }
55
56    /** Current position in bits. */
57    public function getBitPosition(): int
58    {
59        return $this->bitPos;
60    }
61
62    /** Current position in bytes (rounded down). */
63    public function getBytePosition(): int
64    {
65        return intdiv($this->bitPos, 8);
66    }
67}