![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/app/code/Chronopost/Chronorelais/Lib/Fpdi/PdfParser/CrossReference/ |
<?php /** * This file is part of FPDI * * @package Chronopost\Chronorelais\Lib\Fpdi * @copyright Copyright (c) 2020 Chronopost\Chronorelais\Lib GmbH & Co. KG (https://www.Chronopost\Chronorelais\Lib.com) * @license http://opensource.org/licenses/mit-license The MIT License */ namespace Chronopost\Chronorelais\Lib\Fpdi\PdfParser\CrossReference; use Chronopost\Chronorelais\Lib\Fpdi\PdfParser\PdfParser; use Chronopost\Chronorelais\Lib\Fpdi\PdfParser\StreamReader; use Chronopost\Chronorelais\Lib\Fpdi\PdfParser\Type\PdfTypeException; use function count; use function current; use function sscanf; use function strlen; use function strpos; use function substr; use function trim; /** * Class FixedReader * * This reader allows a very less overhead parsing of single entries of the cross-reference, because the main entries * are only read when needed and not in a single run. * * @package Chronopost\Chronorelais\Lib\Fpdi\PdfParser\CrossReference */ class FixedReader extends AbstractReader implements ReaderInterface { /** * @var StreamReader */ protected $reader; /** * Data of subsections. * * @var array */ protected $subSections; /** * FixedReader constructor. * * @param PdfParser $parser * @throws CrossReferenceException * @throws PdfTypeException */ public function __construct(PdfParser $parser) { $this->reader = $parser->getStreamReader(); $this->read(); parent::__construct($parser); } /** * Read the cross-reference. * * This reader will only read the subsections in this method. The offsets were resolved individually by this * information. * * @throws CrossReferenceException */ protected function read() { $subSections = []; $startObject = $entryCount = $lastLineStart = null; $validityChecked = false; while (($line = $this->reader->readLine(20)) !== false) { if (strpos($line, 'trailer') !== false) { $this->reader->reset($lastLineStart); break; } // jump over if line content doesn't match the expected string if (sscanf($line, '%d %d', $startObject, $entryCount) !== 2) { continue; } $oldPosition = $this->reader->getPosition(); $position = $oldPosition + $this->reader->getOffset(); if (!$validityChecked && $entryCount > 0) { $nextLine = $this->reader->readBytes(21); /* Check the next line for maximum of 20 bytes and not longer * By catching 21 bytes and trimming the length should be still 21. */ if (strlen(trim($nextLine)) !== 21) { throw new CrossReferenceException( 'Cross-reference entries are larger than 20 bytes.', CrossReferenceException::ENTRIES_TOO_LARGE ); } /* Check for less than 20 bytes: cut the line to 20 bytes and trim; have to result in exactly 18 bytes. * If it would have less bytes the substring would get the first bytes of the next line which would * evaluate to a 20 bytes long string after trimming. */ if (strlen(trim(substr($nextLine, 0, 20))) !== 18) { throw new CrossReferenceException( 'Cross-reference entries are less than 20 bytes.', CrossReferenceException::ENTRIES_TOO_SHORT ); } $validityChecked = true; } $subSections[$position] = [$startObject, $entryCount]; $lastLineStart = $position + $entryCount * 20; $this->reader->reset($lastLineStart); } // reset after the last correct parsed line $this->reader->reset($lastLineStart); if (count($subSections) === 0) { throw new CrossReferenceException( 'No entries found in cross-reference.', CrossReferenceException::NO_ENTRIES ); } $this->subSections = $subSections; } /** * Fixes an invalid object number shift. * * This method can be used to repair documents with an invalid subsection header: * * <code> * xref * 1 7 * 0000000000 65535 f * 0000000009 00000 n * 0000412075 00000 n * 0000412172 00000 n * 0000412359 00000 n * 0000412417 00000 n * 0000412468 00000 n * </code> * * It shall only be called on the first table. * * @return bool */ public function fixFaultySubSectionShift() { $subSections = $this->getSubSections(); if (count($subSections) > 1) { return false; } $subSection = current($subSections); if ($subSection[0] != 1) { return false; } if ($this->getOffsetFor(1) === false) { foreach ($subSections as $offset => list($startObject, $objectCount)) { $this->subSections[$offset] = [$startObject - 1, $objectCount]; } return true; } return false; } /** * Get all subsection data. * * @return array */ public function getSubSections() { return $this->subSections; } /** * @inheritdoc */ public function getOffsetFor($objectNumber) { foreach ($this->subSections as $offset => list($startObject, $objectCount)) { if ($objectNumber >= $startObject && $objectNumber < ($startObject + $objectCount)) { $position = $offset + 20 * ($objectNumber - $startObject); $this->reader->ensure($position, 20); $line = $this->reader->readBytes(20); if ($line[17] === 'f') { return false; } return (int)substr($line, 0, 10); } } return false; } }