Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 3 /** 4 * This file is part of FPDI 5 * 6 * @package setasign\Fpdi 7 * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com) 8 * @license http://opensource.org/licenses/mit-license The MIT License 9 */ 10 11 namespace setasign\Fpdi\PdfParser\CrossReference; 12 13 use setasign\Fpdi\PdfParser\PdfParser; 14 use setasign\Fpdi\PdfParser\StreamReader; 15 16 /** 17 * Class LineReader 18 * 19 * This reader class read all cross-reference entries in a single run. 20 * It supports reading cross-references with e.g. invalid data (e.g. entries with a length < or > 20 bytes). 21 */ 22 class LineReader extends AbstractReader implements ReaderInterface 23 { 24 /** 25 * The object offsets. 26 * 27 * @var array 28 */ 29 protected $offsets; 30 31 /** 32 * LineReader constructor. 33 * 34 * @param PdfParser $parser 35 * @throws CrossReferenceException 36 */ 37 public function __construct(PdfParser $parser) 38 { 39 $this->read($this->extract($parser->getStreamReader())); 40 parent::__construct($parser); 41 } 42 43 /** 44 * @inheritdoc 45 * @return int|false 46 */ 47 public function getOffsetFor($objectNumber) 48 { 49 if (isset($this->offsets[$objectNumber])) { 50 return $this->offsets[$objectNumber][0]; 51 } 52 53 return false; 54 } 55 56 /** 57 * Get all found offsets. 58 * 59 * @return array 60 */ 61 public function getOffsets() 62 { 63 return $this->offsets; 64 } 65 66 /** 67 * Extracts the cross reference data from the stream reader. 68 * 69 * @param StreamReader $reader 70 * @return string 71 * @throws CrossReferenceException 72 */ 73 protected function extract(StreamReader $reader) 74 { 75 $bytesPerCycle = 100; 76 $reader->reset(null, $bytesPerCycle); 77 78 $cycles = 0; 79 do { 80 // 6 = length of "trailer" - 1 81 $pos = \max(($bytesPerCycle * $cycles) - 6, 0); 82 $trailerPos = \strpos($reader->getBuffer(false), 'trailer', $pos); 83 $cycles++; 84 } while ($trailerPos === false && $reader->increaseLength($bytesPerCycle) !== false); 85 86 if ($trailerPos === false) { 87 throw new CrossReferenceException( 88 'Unexpected end of cross reference. "trailer"-keyword not found.', 89 CrossReferenceException::NO_TRAILER_FOUND 90 ); 91 } 92 93 $xrefContent = \substr($reader->getBuffer(false), 0, $trailerPos); 94 $reader->reset($reader->getPosition() + $trailerPos); 95 96 return $xrefContent; 97 } 98 99 /** 100 * Read the cross-reference entries. 101 * 102 * @param string $xrefContent 103 * @throws CrossReferenceException 104 */ 105 protected function read($xrefContent) 106 { 107 // get eol markers in the first 100 bytes 108 \preg_match_all("/(\r\n|\n|\r)/", \substr($xrefContent, 0, 100), $m); 109 110 if (\count($m[0]) === 0) { 111 throw new CrossReferenceException( 112 'No data found in cross-reference.', 113 CrossReferenceException::INVALID_DATA 114 ); 115 } 116 117 // count(array_count_values()) is faster then count(array_unique()) 118 // @see https://github.com/symfony/symfony/pull/23731 119 // can be reverted for php7.2 120 $differentLineEndings = \count(\array_count_values($m[0])); 121 if ($differentLineEndings > 1) { 122 $lines = \preg_split("/(\r\n|\n|\r)/", $xrefContent, -1, PREG_SPLIT_NO_EMPTY); 123 } else { 124 $lines = \explode($m[0][0], $xrefContent); 125 } 126 127 unset($differentLineEndings, $m); 128 if (!\is_array($lines)) { 129 $this->offsets = []; 130 return; 131 } 132 133 $start = 0; 134 $offsets = []; 135 136 // trim all lines and remove empty lines 137 $lines = \array_filter(\array_map('\trim', $lines)); 138 foreach ($lines as $line) { 139 $pieces = \explode(' ', $line); 140 141 switch (\count($pieces)) { 142 case 2: 143 $start = (int) $pieces[0]; 144 break; 145 146 case 3: 147 switch ($pieces[2]) { 148 case 'n': 149 $offsets[$start] = [(int) $pieces[0], (int) $pieces[1]]; 150 $start++; 151 break 2; 152 case 'f': 153 $start++; 154 break 2; 155 } 156 // fall through if pieces doesn't match 157 158 default: 159 throw new CrossReferenceException( 160 \sprintf('Unexpected data in xref table (%s)', \implode(' ', $pieces)), 161 CrossReferenceException::INVALID_DATA 162 ); 163 } 164 } 165 166 $this->offsets = $offsets; 167 } 168 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body