Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
CrossReferenceTable
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
3 / 3
4
100.00% covered (success)
100.00%
1 / 1
 add
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEntries
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 build
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Phpdftk\Pdf\Core\File;
6
7/**
8 * Builds the classic PDF cross-reference table (ISO 32000-2 section 7.5.4).
9 *
10 * The fixed 20-byte entry width is mandated by the spec so that readers can
11 * seek directly to any entry by index without parsing the entire table:
12 *
13 *   OOOOOOOOOO GGGGG n \r\n   (in-use object: O = 10-digit byte offset)
14 *   OOOOOOOOOO GGGGG f \r\n   (free object: O = next free object number)
15 *
16 * Object 0 is always emitted as the free-list head with generation 65535,
17 * which signals that it can never be reused.
18 */
19class CrossReferenceTable
20{
21    /** @var array<int, int> objectNumber => byte offset */
22    private array $entries = [];
23
24    /**
25     * Record the byte offset for an in-use object.
26     */
27    public function add(int $objNum, int $offset): void
28    {
29        $this->entries[$objNum] = $offset;
30    }
31
32    /**
33     * Return recorded entries (objectNumber => byte offset).
34     *
35     * @return array<int, int>
36     */
37    public function getEntries(): array
38    {
39        return $this->entries;
40    }
41
42    /**
43     * Build and return the complete xref section as a string.
44     * The returned string starts with "xref\n" and ends with the last entry (no trailing newline).
45     */
46    public function build(int $size): string
47    {
48        $xref = "xref\n";
49        $xref .= sprintf("0 %d\n", $size);
50
51        // Object 0: free list head â€” generation 65535, free
52        $xref .= "0000000000 65535 f \r\n";
53
54        // Objects 1..N
55        for ($i = 1; $i < $size; $i++) {
56            $offset = $this->entries[$i] ?? 0;
57            // Each entry is exactly 20 bytes: 10 + space + 5 + space + n/f + space + CR + LF
58            $xref .= sprintf("%010d 00000 n \r\n", $offset);
59        }
60
61        return $xref;
62    }
63}