Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
PageOffsetHintTable
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
2 / 2
6
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
 getPageByteRange
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Pdf\Reader\Parser;
6
7/**
8 * Parsed page offset hint table — ISO 32000-2 §F.4.1.
9 *
10 * Contains the header values (minimums and bit widths) and per-page entries
11 * for computing byte ranges of individual pages in a linearized PDF.
12 */
13final class PageOffsetHintTable
14{
15    /**
16     * @param list<PageHintEntry> $entries
17     */
18    public function __construct(
19        public readonly int $minObjectsPerPage,
20        public readonly int $firstPageLocation,
21        public readonly int $minPageLength,
22        public readonly int $minSharedRefsPerPage,
23        public readonly int $minSharedObjId,
24        public readonly int $minContentStreamOffset,
25        public readonly int $minContentStreamLength,
26        public readonly array $entries,
27    ) {}
28
29    /**
30     * Compute the byte offset and length for a page (0-indexed).
31     *
32     * @return array{offset: int, length: int}
33     */
34    public function getPageByteRange(int $pageIndex): array
35    {
36        if ($pageIndex < 0 || $pageIndex >= count($this->entries)) {
37            throw new \OutOfRangeException("Page index {$pageIndex} out of range");
38        }
39
40        // For the first page (index 0), the location is the firstPageLocation
41        // For subsequent pages, we sum up lengths starting from after firstPageEnd
42        if ($pageIndex === 0) {
43            $length = $this->minPageLength + $this->entries[0]->pageLengthDelta;
44            return ['offset' => $this->firstPageLocation, 'length' => $length];
45        }
46
47        // Pages after the first are sequential in the file, starting after
48        // the first-page section. Their offsets are cumulative.
49        $offset = 0;
50        for ($i = 1; $i < $pageIndex; $i++) {
51            $offset += $this->minPageLength + $this->entries[$i]->pageLengthDelta;
52        }
53
54        $length = $this->minPageLength + $this->entries[$pageIndex]->pageLengthDelta;
55
56        return ['offset' => $offset, 'length' => $length];
57    }
58}