PdfDictionary.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <?php
  2. /**
  3. * This file is part of FPDI
  4. *
  5. * @package Fpdi
  6. * @copyright Copyright (c) 2020 Setasign GmbH & Co. KG (https://www.setasign.com)
  7. * @license http://opensource.org/licenses/mit-license The MIT License
  8. */
  9. namespace Fpdi\PdfParser\Type;
  10. use Fpdi\PdfParser\PdfParser;
  11. use Fpdi\PdfParser\StreamReader;
  12. use Fpdi\PdfParser\Tokenizer;
  13. /**
  14. * Class representing a PDF dictionary object
  15. */
  16. class PdfDictionary extends PdfType
  17. {
  18. /**
  19. * Parses a dictionary of the passed tokenizer, stream-reader and parser.
  20. *
  21. * @param Tokenizer $tokenizer
  22. * @param StreamReader $streamReader
  23. * @param PdfParser $parser
  24. * @return bool|self
  25. * @throws PdfTypeException
  26. */
  27. public static function parse(Tokenizer $tokenizer, StreamReader $streamReader, PdfParser $parser)
  28. {
  29. $entries = [];
  30. while (true) {
  31. $token = $tokenizer->getNextToken();
  32. if ($token === '>' && $streamReader->getByte() === '>') {
  33. $streamReader->addOffset(1);
  34. break;
  35. }
  36. $key = $parser->readValue($token);
  37. if ($key === false) {
  38. return false;
  39. }
  40. // ensure the first value to be a Name object
  41. if (!($key instanceof PdfName)) {
  42. $lastToken = null;
  43. // ignore all other entries and search for the closing brackets
  44. while (($token = $tokenizer->getNextToken()) !== '>' && $token !== false && $lastToken !== '>') {
  45. $lastToken = $token;
  46. }
  47. if ($token === false) {
  48. return false;
  49. }
  50. break;
  51. }
  52. $value = $parser->readValue();
  53. if ($value === false) {
  54. return false;
  55. }
  56. if ($value instanceof PdfNull) {
  57. continue;
  58. }
  59. // catch missing value
  60. if ($value instanceof PdfToken && $value->value === '>' && $streamReader->getByte() === '>') {
  61. $streamReader->addOffset(1);
  62. break;
  63. }
  64. $entries[$key->value] = $value;
  65. }
  66. $v = new self();
  67. $v->value = $entries;
  68. return $v;
  69. }
  70. /**
  71. * Helper method to create an instance.
  72. *
  73. * @param PdfType[] $entries The keys are the name entries of the dictionary.
  74. * @return self
  75. */
  76. public static function create(array $entries = [])
  77. {
  78. $v = new self();
  79. $v->value = $entries;
  80. return $v;
  81. }
  82. /**
  83. * Get a value by its key from a dictionary or a default value.
  84. *
  85. * @param mixed $dictionary
  86. * @param string $key
  87. * @param PdfType|null $default
  88. * @return PdfNull|PdfType
  89. * @throws PdfTypeException
  90. */
  91. public static function get($dictionary, $key, PdfType $default = null)
  92. {
  93. $dictionary = self::ensure($dictionary);
  94. if (isset($dictionary->value[$key])) {
  95. return $dictionary->value[$key];
  96. }
  97. return $default === null
  98. ? new PdfNull()
  99. : $default;
  100. }
  101. /**
  102. * Ensures that the passed value is a PdfDictionary instance.
  103. *
  104. * @param mixed $dictionary
  105. * @return self
  106. * @throws PdfTypeException
  107. */
  108. public static function ensure($dictionary)
  109. {
  110. return PdfType::ensureType(self::class, $dictionary, 'Dictionary value expected.');
  111. }
  112. }