1*dc4d9dc6SAnna Dabrowska<?php 2*dc4d9dc6SAnna Dabrowska/** 3*dc4d9dc6SAnna Dabrowska * This file is part of FPDI 4*dc4d9dc6SAnna Dabrowska * 5*dc4d9dc6SAnna Dabrowska * @package setasign\Fpdi 6*dc4d9dc6SAnna Dabrowska * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com) 7*dc4d9dc6SAnna Dabrowska * @license http://opensource.org/licenses/mit-license The MIT License 8*dc4d9dc6SAnna Dabrowska */ 9*dc4d9dc6SAnna Dabrowska 10*dc4d9dc6SAnna Dabrowskanamespace setasign\Fpdi\PdfParser; 11*dc4d9dc6SAnna Dabrowska 12*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\CrossReference\CrossReference; 13*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException; 14*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfArray; 15*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfBoolean; 16*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfDictionary; 17*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfHexString; 18*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfIndirectObject; 19*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfIndirectObjectReference; 20*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfName; 21*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfNull; 22*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfNumeric; 23*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfString; 24*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfToken; 25*dc4d9dc6SAnna Dabrowskause setasign\Fpdi\PdfParser\Type\PdfType; 26*dc4d9dc6SAnna Dabrowska 27*dc4d9dc6SAnna Dabrowska/** 28*dc4d9dc6SAnna Dabrowska * A PDF parser class 29*dc4d9dc6SAnna Dabrowska * 30*dc4d9dc6SAnna Dabrowska * @package setasign\Fpdi\PdfParser 31*dc4d9dc6SAnna Dabrowska */ 32*dc4d9dc6SAnna Dabrowskaclass PdfParser 33*dc4d9dc6SAnna Dabrowska{ 34*dc4d9dc6SAnna Dabrowska /** 35*dc4d9dc6SAnna Dabrowska * @var StreamReader 36*dc4d9dc6SAnna Dabrowska */ 37*dc4d9dc6SAnna Dabrowska protected $streamReader; 38*dc4d9dc6SAnna Dabrowska 39*dc4d9dc6SAnna Dabrowska /** 40*dc4d9dc6SAnna Dabrowska * @var Tokenizer 41*dc4d9dc6SAnna Dabrowska */ 42*dc4d9dc6SAnna Dabrowska protected $tokenizer; 43*dc4d9dc6SAnna Dabrowska 44*dc4d9dc6SAnna Dabrowska /** 45*dc4d9dc6SAnna Dabrowska * The file header. 46*dc4d9dc6SAnna Dabrowska * 47*dc4d9dc6SAnna Dabrowska * @var string 48*dc4d9dc6SAnna Dabrowska */ 49*dc4d9dc6SAnna Dabrowska protected $fileHeader; 50*dc4d9dc6SAnna Dabrowska 51*dc4d9dc6SAnna Dabrowska /** 52*dc4d9dc6SAnna Dabrowska * The offset to the file header. 53*dc4d9dc6SAnna Dabrowska * 54*dc4d9dc6SAnna Dabrowska * @var int 55*dc4d9dc6SAnna Dabrowska */ 56*dc4d9dc6SAnna Dabrowska protected $fileHeaderOffset; 57*dc4d9dc6SAnna Dabrowska 58*dc4d9dc6SAnna Dabrowska /** 59*dc4d9dc6SAnna Dabrowska * @var CrossReference 60*dc4d9dc6SAnna Dabrowska */ 61*dc4d9dc6SAnna Dabrowska protected $xref; 62*dc4d9dc6SAnna Dabrowska 63*dc4d9dc6SAnna Dabrowska /** 64*dc4d9dc6SAnna Dabrowska * All read objects. 65*dc4d9dc6SAnna Dabrowska * 66*dc4d9dc6SAnna Dabrowska * @var array 67*dc4d9dc6SAnna Dabrowska */ 68*dc4d9dc6SAnna Dabrowska protected $objects = []; 69*dc4d9dc6SAnna Dabrowska 70*dc4d9dc6SAnna Dabrowska /** 71*dc4d9dc6SAnna Dabrowska * PdfParser constructor. 72*dc4d9dc6SAnna Dabrowska * 73*dc4d9dc6SAnna Dabrowska * @param StreamReader $streamReader 74*dc4d9dc6SAnna Dabrowska */ 75*dc4d9dc6SAnna Dabrowska public function __construct(StreamReader $streamReader) 76*dc4d9dc6SAnna Dabrowska { 77*dc4d9dc6SAnna Dabrowska $this->streamReader = $streamReader; 78*dc4d9dc6SAnna Dabrowska $this->tokenizer = new Tokenizer($streamReader); 79*dc4d9dc6SAnna Dabrowska } 80*dc4d9dc6SAnna Dabrowska 81*dc4d9dc6SAnna Dabrowska /** 82*dc4d9dc6SAnna Dabrowska * Removes cycled references. 83*dc4d9dc6SAnna Dabrowska * 84*dc4d9dc6SAnna Dabrowska * @internal 85*dc4d9dc6SAnna Dabrowska */ 86*dc4d9dc6SAnna Dabrowska public function cleanUp() 87*dc4d9dc6SAnna Dabrowska { 88*dc4d9dc6SAnna Dabrowska $this->xref = null; 89*dc4d9dc6SAnna Dabrowska } 90*dc4d9dc6SAnna Dabrowska 91*dc4d9dc6SAnna Dabrowska /** 92*dc4d9dc6SAnna Dabrowska * Get the stream reader instance. 93*dc4d9dc6SAnna Dabrowska * 94*dc4d9dc6SAnna Dabrowska * @return StreamReader 95*dc4d9dc6SAnna Dabrowska */ 96*dc4d9dc6SAnna Dabrowska public function getStreamReader() 97*dc4d9dc6SAnna Dabrowska { 98*dc4d9dc6SAnna Dabrowska return $this->streamReader; 99*dc4d9dc6SAnna Dabrowska } 100*dc4d9dc6SAnna Dabrowska 101*dc4d9dc6SAnna Dabrowska /** 102*dc4d9dc6SAnna Dabrowska * Get the tokenizer instance. 103*dc4d9dc6SAnna Dabrowska * 104*dc4d9dc6SAnna Dabrowska * @return Tokenizer 105*dc4d9dc6SAnna Dabrowska */ 106*dc4d9dc6SAnna Dabrowska public function getTokenizer() 107*dc4d9dc6SAnna Dabrowska { 108*dc4d9dc6SAnna Dabrowska return $this->tokenizer; 109*dc4d9dc6SAnna Dabrowska } 110*dc4d9dc6SAnna Dabrowska 111*dc4d9dc6SAnna Dabrowska /** 112*dc4d9dc6SAnna Dabrowska * Resolves the file header. 113*dc4d9dc6SAnna Dabrowska * 114*dc4d9dc6SAnna Dabrowska * @throws PdfParserException 115*dc4d9dc6SAnna Dabrowska * @return int 116*dc4d9dc6SAnna Dabrowska */ 117*dc4d9dc6SAnna Dabrowska protected function resolveFileHeader() 118*dc4d9dc6SAnna Dabrowska { 119*dc4d9dc6SAnna Dabrowska if ($this->fileHeader) { 120*dc4d9dc6SAnna Dabrowska return $this->fileHeaderOffset; 121*dc4d9dc6SAnna Dabrowska } 122*dc4d9dc6SAnna Dabrowska 123*dc4d9dc6SAnna Dabrowska $this->streamReader->reset(0); 124*dc4d9dc6SAnna Dabrowska $offset = false; 125*dc4d9dc6SAnna Dabrowska $maxIterations = 1000; 126*dc4d9dc6SAnna Dabrowska while (true) { 127*dc4d9dc6SAnna Dabrowska $buffer = $this->streamReader->getBuffer(false); 128*dc4d9dc6SAnna Dabrowska $offset = \strpos($buffer, '%PDF-'); 129*dc4d9dc6SAnna Dabrowska if ($offset === false) { 130*dc4d9dc6SAnna Dabrowska if (!$this->streamReader->increaseLength(100) || (--$maxIterations === 0)) { 131*dc4d9dc6SAnna Dabrowska throw new PdfParserException( 132*dc4d9dc6SAnna Dabrowska 'Unable to find PDF file header.', 133*dc4d9dc6SAnna Dabrowska PdfParserException::FILE_HEADER_NOT_FOUND 134*dc4d9dc6SAnna Dabrowska ); 135*dc4d9dc6SAnna Dabrowska } 136*dc4d9dc6SAnna Dabrowska continue; 137*dc4d9dc6SAnna Dabrowska } 138*dc4d9dc6SAnna Dabrowska break; 139*dc4d9dc6SAnna Dabrowska } 140*dc4d9dc6SAnna Dabrowska 141*dc4d9dc6SAnna Dabrowska $this->fileHeaderOffset = $offset; 142*dc4d9dc6SAnna Dabrowska $this->streamReader->setOffset($offset); 143*dc4d9dc6SAnna Dabrowska 144*dc4d9dc6SAnna Dabrowska $this->fileHeader = \trim($this->streamReader->readLine()); 145*dc4d9dc6SAnna Dabrowska return $this->fileHeaderOffset; 146*dc4d9dc6SAnna Dabrowska } 147*dc4d9dc6SAnna Dabrowska 148*dc4d9dc6SAnna Dabrowska /** 149*dc4d9dc6SAnna Dabrowska * Get the cross reference instance. 150*dc4d9dc6SAnna Dabrowska * 151*dc4d9dc6SAnna Dabrowska * @return CrossReference 152*dc4d9dc6SAnna Dabrowska * @throws CrossReferenceException 153*dc4d9dc6SAnna Dabrowska * @throws PdfParserException 154*dc4d9dc6SAnna Dabrowska */ 155*dc4d9dc6SAnna Dabrowska public function getCrossReference() 156*dc4d9dc6SAnna Dabrowska { 157*dc4d9dc6SAnna Dabrowska if ($this->xref === null) { 158*dc4d9dc6SAnna Dabrowska $this->xref = new CrossReference($this, $this->resolveFileHeader()); 159*dc4d9dc6SAnna Dabrowska } 160*dc4d9dc6SAnna Dabrowska 161*dc4d9dc6SAnna Dabrowska return $this->xref; 162*dc4d9dc6SAnna Dabrowska } 163*dc4d9dc6SAnna Dabrowska 164*dc4d9dc6SAnna Dabrowska /** 165*dc4d9dc6SAnna Dabrowska * Get the PDF version. 166*dc4d9dc6SAnna Dabrowska * 167*dc4d9dc6SAnna Dabrowska * @return int[] An array of major and minor version. 168*dc4d9dc6SAnna Dabrowska * @throws PdfParserException 169*dc4d9dc6SAnna Dabrowska */ 170*dc4d9dc6SAnna Dabrowska public function getPdfVersion() 171*dc4d9dc6SAnna Dabrowska { 172*dc4d9dc6SAnna Dabrowska $this->resolveFileHeader(); 173*dc4d9dc6SAnna Dabrowska 174*dc4d9dc6SAnna Dabrowska if (\preg_match('/%PDF-(\d)\.(\d)/', $this->fileHeader, $result) === 0) { 175*dc4d9dc6SAnna Dabrowska throw new PdfParserException( 176*dc4d9dc6SAnna Dabrowska 'Unable to extract PDF version from file header.', 177*dc4d9dc6SAnna Dabrowska PdfParserException::PDF_VERSION_NOT_FOUND 178*dc4d9dc6SAnna Dabrowska ); 179*dc4d9dc6SAnna Dabrowska } 180*dc4d9dc6SAnna Dabrowska list(, $major, $minor) = $result; 181*dc4d9dc6SAnna Dabrowska 182*dc4d9dc6SAnna Dabrowska $catalog = $this->getCatalog(); 183*dc4d9dc6SAnna Dabrowska if (isset($catalog->value['Version'])) { 184*dc4d9dc6SAnna Dabrowska $versionParts = \explode('.', PdfName::unescape(PdfType::resolve($catalog->value['Version'], $this)->value)); 185*dc4d9dc6SAnna Dabrowska if (count($versionParts) === 2) { 186*dc4d9dc6SAnna Dabrowska list($major, $minor) = $versionParts; 187*dc4d9dc6SAnna Dabrowska } 188*dc4d9dc6SAnna Dabrowska } 189*dc4d9dc6SAnna Dabrowska 190*dc4d9dc6SAnna Dabrowska return [(int) $major, (int) $minor]; 191*dc4d9dc6SAnna Dabrowska } 192*dc4d9dc6SAnna Dabrowska 193*dc4d9dc6SAnna Dabrowska /** 194*dc4d9dc6SAnna Dabrowska * Get the catalog dictionary. 195*dc4d9dc6SAnna Dabrowska * 196*dc4d9dc6SAnna Dabrowska * @return PdfDictionary 197*dc4d9dc6SAnna Dabrowska * @throws Type\PdfTypeException 198*dc4d9dc6SAnna Dabrowska * @throws CrossReferenceException 199*dc4d9dc6SAnna Dabrowska * @throws PdfParserException 200*dc4d9dc6SAnna Dabrowska */ 201*dc4d9dc6SAnna Dabrowska public function getCatalog() 202*dc4d9dc6SAnna Dabrowska { 203*dc4d9dc6SAnna Dabrowska $xref = $this->getCrossReference(); 204*dc4d9dc6SAnna Dabrowska $trailer = $xref->getTrailer(); 205*dc4d9dc6SAnna Dabrowska 206*dc4d9dc6SAnna Dabrowska $catalog = PdfType::resolve(PdfDictionary::get($trailer, 'Root'), $this); 207*dc4d9dc6SAnna Dabrowska 208*dc4d9dc6SAnna Dabrowska return PdfDictionary::ensure($catalog); 209*dc4d9dc6SAnna Dabrowska } 210*dc4d9dc6SAnna Dabrowska 211*dc4d9dc6SAnna Dabrowska /** 212*dc4d9dc6SAnna Dabrowska * Get an indirect object by its object number. 213*dc4d9dc6SAnna Dabrowska * 214*dc4d9dc6SAnna Dabrowska * @param int $objectNumber 215*dc4d9dc6SAnna Dabrowska * @param bool $cache 216*dc4d9dc6SAnna Dabrowska * @return PdfIndirectObject 217*dc4d9dc6SAnna Dabrowska * @throws CrossReferenceException 218*dc4d9dc6SAnna Dabrowska * @throws PdfParserException 219*dc4d9dc6SAnna Dabrowska */ 220*dc4d9dc6SAnna Dabrowska public function getIndirectObject($objectNumber, $cache = false) 221*dc4d9dc6SAnna Dabrowska { 222*dc4d9dc6SAnna Dabrowska $objectNumber = (int) $objectNumber; 223*dc4d9dc6SAnna Dabrowska if (isset($this->objects[$objectNumber])) { 224*dc4d9dc6SAnna Dabrowska return $this->objects[$objectNumber]; 225*dc4d9dc6SAnna Dabrowska } 226*dc4d9dc6SAnna Dabrowska 227*dc4d9dc6SAnna Dabrowska $xref = $this->getCrossReference(); 228*dc4d9dc6SAnna Dabrowska $object = $xref->getIndirectObject($objectNumber); 229*dc4d9dc6SAnna Dabrowska 230*dc4d9dc6SAnna Dabrowska if ($cache) { 231*dc4d9dc6SAnna Dabrowska $this->objects[$objectNumber] = $object; 232*dc4d9dc6SAnna Dabrowska } 233*dc4d9dc6SAnna Dabrowska 234*dc4d9dc6SAnna Dabrowska return $object; 235*dc4d9dc6SAnna Dabrowska } 236*dc4d9dc6SAnna Dabrowska 237*dc4d9dc6SAnna Dabrowska /** 238*dc4d9dc6SAnna Dabrowska * Read a PDF value. 239*dc4d9dc6SAnna Dabrowska * 240*dc4d9dc6SAnna Dabrowska * @param null|bool|string $token 241*dc4d9dc6SAnna Dabrowska * @param null|string $expectedType 242*dc4d9dc6SAnna Dabrowska * @return bool|PdfArray|PdfBoolean|PdfHexString|PdfName|PdfNull|PdfNumeric|PdfString|PdfToken|PdfIndirectObjectReference 243*dc4d9dc6SAnna Dabrowska * @throws Type\PdfTypeException 244*dc4d9dc6SAnna Dabrowska */ 245*dc4d9dc6SAnna Dabrowska public function readValue($token = null, $expectedType = null) 246*dc4d9dc6SAnna Dabrowska { 247*dc4d9dc6SAnna Dabrowska if ($token === null) { 248*dc4d9dc6SAnna Dabrowska $token = $this->tokenizer->getNextToken(); 249*dc4d9dc6SAnna Dabrowska } 250*dc4d9dc6SAnna Dabrowska 251*dc4d9dc6SAnna Dabrowska if ($token === false) { 252*dc4d9dc6SAnna Dabrowska if ($expectedType !== null) { 253*dc4d9dc6SAnna Dabrowska throw new Type\PdfTypeException('Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE); 254*dc4d9dc6SAnna Dabrowska } 255*dc4d9dc6SAnna Dabrowska return false; 256*dc4d9dc6SAnna Dabrowska } 257*dc4d9dc6SAnna Dabrowska 258*dc4d9dc6SAnna Dabrowska switch ($token) { 259*dc4d9dc6SAnna Dabrowska case '(': 260*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType($token, $expectedType); 261*dc4d9dc6SAnna Dabrowska return PdfString::parse($this->streamReader); 262*dc4d9dc6SAnna Dabrowska 263*dc4d9dc6SAnna Dabrowska case '<': 264*dc4d9dc6SAnna Dabrowska if ($this->streamReader->getByte() === '<') { 265*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType('<<', $expectedType); 266*dc4d9dc6SAnna Dabrowska $this->streamReader->addOffset(1); 267*dc4d9dc6SAnna Dabrowska return PdfDictionary::parse($this->tokenizer, $this->streamReader, $this); 268*dc4d9dc6SAnna Dabrowska } 269*dc4d9dc6SAnna Dabrowska 270*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType($token, $expectedType); 271*dc4d9dc6SAnna Dabrowska return PdfHexString::parse($this->streamReader); 272*dc4d9dc6SAnna Dabrowska 273*dc4d9dc6SAnna Dabrowska case '/': 274*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType($token, $expectedType); 275*dc4d9dc6SAnna Dabrowska return PdfName::parse($this->tokenizer, $this->streamReader); 276*dc4d9dc6SAnna Dabrowska 277*dc4d9dc6SAnna Dabrowska case '[': 278*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType($token, $expectedType); 279*dc4d9dc6SAnna Dabrowska return PdfArray::parse($this->tokenizer, $this); 280*dc4d9dc6SAnna Dabrowska 281*dc4d9dc6SAnna Dabrowska default: 282*dc4d9dc6SAnna Dabrowska if (\is_numeric($token)) { 283*dc4d9dc6SAnna Dabrowska if (($token2 = $this->tokenizer->getNextToken()) !== false) { 284*dc4d9dc6SAnna Dabrowska if (\is_numeric($token2)) { 285*dc4d9dc6SAnna Dabrowska if (($token3 = $this->tokenizer->getNextToken()) !== false) { 286*dc4d9dc6SAnna Dabrowska switch ($token3) { 287*dc4d9dc6SAnna Dabrowska case 'obj': 288*dc4d9dc6SAnna Dabrowska if ($expectedType !== null && $expectedType !== PdfIndirectObject::class) { 289*dc4d9dc6SAnna Dabrowska throw new Type\PdfTypeException( 290*dc4d9dc6SAnna Dabrowska 'Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE 291*dc4d9dc6SAnna Dabrowska ); 292*dc4d9dc6SAnna Dabrowska } 293*dc4d9dc6SAnna Dabrowska 294*dc4d9dc6SAnna Dabrowska return PdfIndirectObject::parse( 295*dc4d9dc6SAnna Dabrowska $token, 296*dc4d9dc6SAnna Dabrowska $token2, 297*dc4d9dc6SAnna Dabrowska $this, 298*dc4d9dc6SAnna Dabrowska $this->tokenizer, 299*dc4d9dc6SAnna Dabrowska $this->streamReader 300*dc4d9dc6SAnna Dabrowska ); 301*dc4d9dc6SAnna Dabrowska case 'R': 302*dc4d9dc6SAnna Dabrowska if ($expectedType !== null && 303*dc4d9dc6SAnna Dabrowska $expectedType !== PdfIndirectObjectReference::class 304*dc4d9dc6SAnna Dabrowska ) { 305*dc4d9dc6SAnna Dabrowska throw new Type\PdfTypeException( 306*dc4d9dc6SAnna Dabrowska 'Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE 307*dc4d9dc6SAnna Dabrowska ); 308*dc4d9dc6SAnna Dabrowska } 309*dc4d9dc6SAnna Dabrowska 310*dc4d9dc6SAnna Dabrowska return PdfIndirectObjectReference::create($token, $token2); 311*dc4d9dc6SAnna Dabrowska } 312*dc4d9dc6SAnna Dabrowska 313*dc4d9dc6SAnna Dabrowska $this->tokenizer->pushStack($token3); 314*dc4d9dc6SAnna Dabrowska } 315*dc4d9dc6SAnna Dabrowska } 316*dc4d9dc6SAnna Dabrowska 317*dc4d9dc6SAnna Dabrowska $this->tokenizer->pushStack($token2); 318*dc4d9dc6SAnna Dabrowska } 319*dc4d9dc6SAnna Dabrowska 320*dc4d9dc6SAnna Dabrowska if ($expectedType !== null && $expectedType !== PdfNumeric::class) { 321*dc4d9dc6SAnna Dabrowska throw new Type\PdfTypeException( 322*dc4d9dc6SAnna Dabrowska 'Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE 323*dc4d9dc6SAnna Dabrowska ); 324*dc4d9dc6SAnna Dabrowska } 325*dc4d9dc6SAnna Dabrowska return PdfNumeric::create($token); 326*dc4d9dc6SAnna Dabrowska } 327*dc4d9dc6SAnna Dabrowska 328*dc4d9dc6SAnna Dabrowska if ($token === 'true' || $token === 'false') { 329*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType($token, $expectedType); 330*dc4d9dc6SAnna Dabrowska return PdfBoolean::create($token === 'true'); 331*dc4d9dc6SAnna Dabrowska } 332*dc4d9dc6SAnna Dabrowska 333*dc4d9dc6SAnna Dabrowska if ($token === 'null') { 334*dc4d9dc6SAnna Dabrowska $this->ensureExpectedType($token, $expectedType); 335*dc4d9dc6SAnna Dabrowska return new PdfNull(); 336*dc4d9dc6SAnna Dabrowska } 337*dc4d9dc6SAnna Dabrowska 338*dc4d9dc6SAnna Dabrowska if ($expectedType !== null && $expectedType !== PdfToken::class) { 339*dc4d9dc6SAnna Dabrowska throw new Type\PdfTypeException( 340*dc4d9dc6SAnna Dabrowska 'Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE 341*dc4d9dc6SAnna Dabrowska ); 342*dc4d9dc6SAnna Dabrowska } 343*dc4d9dc6SAnna Dabrowska 344*dc4d9dc6SAnna Dabrowska $v = new PdfToken(); 345*dc4d9dc6SAnna Dabrowska $v->value = $token; 346*dc4d9dc6SAnna Dabrowska 347*dc4d9dc6SAnna Dabrowska return $v; 348*dc4d9dc6SAnna Dabrowska } 349*dc4d9dc6SAnna Dabrowska } 350*dc4d9dc6SAnna Dabrowska 351*dc4d9dc6SAnna Dabrowska /** 352*dc4d9dc6SAnna Dabrowska * Ensures that the token will evaluate to an expected object type (or not). 353*dc4d9dc6SAnna Dabrowska * 354*dc4d9dc6SAnna Dabrowska * @param string $token 355*dc4d9dc6SAnna Dabrowska * @param string|null $expectedType 356*dc4d9dc6SAnna Dabrowska * @return bool 357*dc4d9dc6SAnna Dabrowska * @throws Type\PdfTypeException 358*dc4d9dc6SAnna Dabrowska */ 359*dc4d9dc6SAnna Dabrowska private function ensureExpectedType($token, $expectedType) 360*dc4d9dc6SAnna Dabrowska { 361*dc4d9dc6SAnna Dabrowska static $mapping = [ 362*dc4d9dc6SAnna Dabrowska '(' => PdfString::class, 363*dc4d9dc6SAnna Dabrowska '<' => PdfHexString::class, 364*dc4d9dc6SAnna Dabrowska '<<' => PdfDictionary::class, 365*dc4d9dc6SAnna Dabrowska '/' => PdfName::class, 366*dc4d9dc6SAnna Dabrowska '[' => PdfArray::class, 367*dc4d9dc6SAnna Dabrowska 'true' => PdfBoolean::class, 368*dc4d9dc6SAnna Dabrowska 'false' => PdfBoolean::class, 369*dc4d9dc6SAnna Dabrowska 'null' => PdfNull::class 370*dc4d9dc6SAnna Dabrowska ]; 371*dc4d9dc6SAnna Dabrowska 372*dc4d9dc6SAnna Dabrowska if ($expectedType === null || $mapping[$token] === $expectedType) { 373*dc4d9dc6SAnna Dabrowska return true; 374*dc4d9dc6SAnna Dabrowska } 375*dc4d9dc6SAnna Dabrowska 376*dc4d9dc6SAnna Dabrowska throw new Type\PdfTypeException('Got unexpected token type.', Type\PdfTypeException::INVALID_DATA_TYPE); 377*dc4d9dc6SAnna Dabrowska } 378*dc4d9dc6SAnna Dabrowska} 379