* @copyright 2011-2026 Nicola Asuni - Tecnick.com LTD * @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE) * @link https://github.com/tecnickcom/tc-lib-pdf-parser * * This file is part of tc-lib-pdf-parser software library. */ namespace Test; use Com\Tecnick\Pdf\Parser\Parser; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** * Filter Test * * @since 2011-05-23 * @category Library * @package PdfParser * @author Nicola Asuni * @copyright 2011-2026 Nicola Asuni - Tecnick.com LTD * @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE) * @link https://github.com/tecnickcom/tc-lib-pdf-parser */ class ParserTest extends TestCase { /** * @throws \Com\Tecnick\Pdf\Parser\Exception */ #[DataProvider('getParseProvider')] public function testParse(string $filename, string $hash): void { $cfg = [ 'ignore_filter_errors' => true, ]; $rawdata = \file_get_contents($filename); $this->assertNotFalse($rawdata); $parser = new Parser($cfg); $data = $parser->parse($rawdata); $this->assertEquals($hash, \md5(\serialize($data))); } /** * @return array */ public static function getParseProvider(): array { return [ ['resources/test/example_005.pdf', '510a5ea860470dae0781f4bd8d5eb250'], ['resources/test/example_036.pdf', '2869501cf41a4c4a0402c00832329e25'], ['resources/test/example_046.pdf', 'cfaee514b9c09aa282b4e2a8f0061a3d'], ]; } /** * @throws \Com\Tecnick\Pdf\Parser\Exception */ public function testParseHandlesMultiRangeXrefIndexRegression(): void { $parser = new Parser(['ignore_filter_errors' => true]); $data = $parser->parse($this->buildMultiRangeXrefIndexPdf()); $xref = $data[0]; $objects = $data[1]; $this->assertSame('41_0', $xref['trailer']['root']); $this->assertArrayNotHasKey('encrypt', $xref['trailer']); $this->assertNotNull($objects['41_0'][0] ?? null); $this->assertSame('<<', $objects['41_0'][0][0]); $this->assertNotNull($objects['42_0'][0] ?? null); $this->assertSame('<<', $objects['42_0'][0][0]); $this->assertNotNull($objects['43_0'][0] ?? null); $this->assertSame('<<', $objects['43_0'][0][0]); $this->assertSame('7aa83a972ca79bafe26be3620b7512e2', \md5(\serialize($data))); } private function buildMultiRangeXrefIndexPdf(): string { $pdf = "%PDF-1.7\n"; $offsets = []; $addObject = static function (string &$pdfData, array &$objOffsets, int $objNum, string $body): void { $objOffsets[$objNum] = \strlen($pdfData); $pdfData .= $objNum . " 0 obj\n" . $body . "\nendobj\n"; }; $addObject($pdf, $offsets, 3, '<< /Dummy 3 >>'); $addObject($pdf, $offsets, 15, '<< /Dummy 15 >>'); $addObject($pdf, $offsets, 17, '<< /Dummy 17 >>'); $addObject($pdf, $offsets, 18, '<< /Dummy 18 >>'); $addObject($pdf, $offsets, 41, '<< /Type /Catalog /Pages 42 0 R >>'); $addObject($pdf, $offsets, 42, '<< /Type /Pages /Count 1 /Kids [43 0 R] >>'); $addObject($pdf, $offsets, 43, '<< /Type /Page /Parent 42 0 R /MediaBox [0 0 10 10] >>'); $indexObjects = [3, 15, 17, 18, 41, 42, 43]; $bytes = []; foreach ($indexObjects as $objNum) { $offset = (int) ($offsets[$objNum] ?? 0); $bytes[] = 0; $bytes[] = 1; $bytes[] = ($offset >> 16) & 0xff; $bytes[] = ($offset >> 8) & 0xff; $bytes[] = $offset & 0xff; } $stream = \pack('C*', ...$bytes); $streamLen = \strlen($stream); $xrefBody = '<< /Type /XRef' . ' /Size 60' . ' /Root 41 0 R' . ' /Index [3 1 15 1 17 2 41 3]' . ' /W [1 3 0]' . ' /Length ' . $streamLen . ' /DecodeParms << /Columns 4 /Predictor 12 >>' . " >>\nstream\n" . $stream . "\nendstream"; $addObject($pdf, $offsets, 50, $xrefBody); $startxref = (int) ($offsets[50] ?? 0); $pdf .= "startxref\n" . $startxref . "\n%%EOF"; return $pdf; } }