Construct.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <?php
  2. /*
  3. * This file is part of the PHPASN1 library.
  4. *
  5. * Copyright © Friedrich Große <friedrich.grosse@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace FG\ASN1;
  11. use ArrayAccess;
  12. use ArrayIterator;
  13. use Countable;
  14. use FG\ASN1\Exception\ParserException;
  15. use Iterator;
  16. abstract class Construct extends ASNObject implements Countable, ArrayAccess, Iterator, Parsable
  17. {
  18. /** @var \FG\ASN1\ASNObject[] */
  19. protected $children;
  20. private $iteratorPosition;
  21. /**
  22. * @param \FG\ASN1\ASNObject[] $children the variadic type hint is commented due to https://github.com/facebook/hhvm/issues/4858
  23. */
  24. public function __construct(/* HH_FIXME[4858]: variadic + strict */ ...$children)
  25. {
  26. $this->children = $children;
  27. $this->iteratorPosition = 0;
  28. }
  29. public function getContent()
  30. {
  31. return $this->children;
  32. }
  33. #[\ReturnTypeWillChange]
  34. public function rewind()
  35. {
  36. $this->iteratorPosition = 0;
  37. }
  38. #[\ReturnTypeWillChange]
  39. public function current()
  40. {
  41. return $this->children[$this->iteratorPosition];
  42. }
  43. #[\ReturnTypeWillChange]
  44. public function key()
  45. {
  46. return $this->iteratorPosition;
  47. }
  48. #[\ReturnTypeWillChange]
  49. public function next()
  50. {
  51. $this->iteratorPosition++;
  52. }
  53. #[\ReturnTypeWillChange]
  54. public function valid()
  55. {
  56. return isset($this->children[$this->iteratorPosition]);
  57. }
  58. #[\ReturnTypeWillChange]
  59. public function offsetExists($offset)
  60. {
  61. return array_key_exists($offset, $this->children);
  62. }
  63. #[\ReturnTypeWillChange]
  64. public function offsetGet($offset)
  65. {
  66. return $this->children[$offset];
  67. }
  68. #[\ReturnTypeWillChange]
  69. public function offsetSet($offset, $value)
  70. {
  71. if ($offset === null) {
  72. $offset = count($this->children);
  73. }
  74. $this->children[$offset] = $value;
  75. }
  76. #[\ReturnTypeWillChange]
  77. public function offsetUnset($offset)
  78. {
  79. unset($this->children[$offset]);
  80. }
  81. protected function calculateContentLength()
  82. {
  83. $length = 0;
  84. foreach ($this->children as $component) {
  85. $length += $component->getObjectLength();
  86. }
  87. return $length;
  88. }
  89. protected function getEncodedValue()
  90. {
  91. $result = '';
  92. foreach ($this->children as $component) {
  93. $result .= $component->getBinary();
  94. }
  95. return $result;
  96. }
  97. public function addChild(ASNObject $child)
  98. {
  99. $this->children[] = $child;
  100. }
  101. public function addChildren(array $children)
  102. {
  103. foreach ($children as $child) {
  104. $this->addChild($child);
  105. }
  106. }
  107. public function __toString()
  108. {
  109. $nrOfChildren = $this->getNumberOfChildren();
  110. $childString = $nrOfChildren == 1 ? 'child' : 'children';
  111. return "[{$nrOfChildren} {$childString}]";
  112. }
  113. public function getNumberOfChildren()
  114. {
  115. return count($this->children);
  116. }
  117. /**
  118. * @return \FG\ASN1\ASNObject[]
  119. */
  120. public function getChildren()
  121. {
  122. return $this->children;
  123. }
  124. /**
  125. * @return \FG\ASN1\ASNObject
  126. */
  127. public function getFirstChild()
  128. {
  129. return $this->children[0];
  130. }
  131. /**
  132. * @param string $binaryData
  133. * @param int $offsetIndex
  134. *
  135. * @throws Exception\ParserException
  136. *
  137. * @return Construct|static
  138. */
  139. #[\ReturnTypeWillChange]
  140. public static function fromBinary(&$binaryData, &$offsetIndex = 0)
  141. {
  142. $parsedObject = new static();
  143. self::parseIdentifier($binaryData[$offsetIndex], $parsedObject->getType(), $offsetIndex++);
  144. $contentLength = self::parseContentLength($binaryData, $offsetIndex);
  145. $startIndex = $offsetIndex;
  146. $children = [];
  147. $octetsToRead = $contentLength;
  148. while ($octetsToRead > 0) {
  149. $newChild = ASNObject::fromBinary($binaryData, $offsetIndex);
  150. $octetsToRead -= $newChild->getObjectLength();
  151. $children[] = $newChild;
  152. }
  153. if ($octetsToRead !== 0) {
  154. throw new ParserException("Sequence length incorrect", $startIndex);
  155. }
  156. $parsedObject->addChildren($children);
  157. $parsedObject->setContentLength($contentLength);
  158. return $parsedObject;
  159. }
  160. #[\ReturnTypeWillChange]
  161. public function count($mode = COUNT_NORMAL)
  162. {
  163. return count($this->children, $mode);
  164. }
  165. public function getIterator()
  166. {
  167. return new ArrayIterator($this->children);
  168. }
  169. }